abcjs 6.1.8 → 6.2.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 (132) hide show
  1. package/RELEASE.md +66 -0
  2. package/dist/abcjs-basic-min.js +2 -2
  3. package/dist/abcjs-basic.js +4373 -4424
  4. package/dist/abcjs-basic.js.map +1 -1
  5. package/dist/abcjs-plugin-min.js +2 -2
  6. package/index.js +1 -1
  7. package/package.json +6 -6
  8. package/plugin.js +1 -1
  9. package/src/api/abc_timing_callbacks.js +7 -3
  10. package/src/api/abc_tunebook_svg.js +1 -2
  11. package/src/data/abc_tune.js +2 -2
  12. package/src/midi/abc_midi_create.js +8 -2
  13. package/src/parse/abc_common.js +0 -47
  14. package/src/parse/abc_parse.js +16 -16
  15. package/src/parse/abc_parse_book.js +3 -3
  16. package/src/parse/abc_parse_directive.js +26 -7
  17. package/src/parse/abc_parse_header.js +11 -9
  18. package/src/parse/abc_parse_key_voice.js +17 -17
  19. package/src/parse/abc_parse_music.js +89 -106
  20. package/src/parse/abc_tokenizer.js +60 -60
  21. package/src/parse/abc_transpose.js +14 -3
  22. package/src/parse/tune-builder.js +19 -14
  23. package/src/synth/abc_midi_flattener.js +25 -9
  24. package/src/synth/abc_midi_sequencer.js +1 -1
  25. package/src/synth/create-synth.js +41 -0
  26. package/src/synth/note-to-midi.js +50 -0
  27. package/src/tablatures/instruments/guitar/tab-guitar.js +0 -2
  28. package/src/tablatures/instruments/string-patterns.js +46 -28
  29. package/src/tablatures/instruments/tab-note.js +26 -103
  30. package/src/tablatures/instruments/violin/tab-violin.js +0 -2
  31. package/src/tablatures/tab-absolute-elements.js +9 -31
  32. package/src/tablatures/tab-renderer.js +2 -2
  33. package/src/test/abc_parser_lint.js +8 -5
  34. package/src/write/README.md +31 -0
  35. package/src/write/creation/abstract-engraver.js +1036 -0
  36. package/src/write/creation/add-chord.js +102 -0
  37. package/src/write/{add-text-if.js → creation/add-text-if.js} +6 -6
  38. package/src/write/{calcHeight.js → creation/calc-height.js} +2 -2
  39. package/src/write/creation/create-clef.js +72 -0
  40. package/src/write/creation/create-key-signature.js +31 -0
  41. package/src/write/creation/create-note-head.js +107 -0
  42. package/src/write/creation/create-time-signature.js +55 -0
  43. package/src/write/creation/decoration.js +357 -0
  44. package/src/write/{abc_absolute_element.js → creation/elements/absolute-element.js} +14 -15
  45. package/src/write/creation/elements/beam-element.js +113 -0
  46. package/src/write/{bottom-text.js → creation/elements/bottom-text.js} +14 -15
  47. package/src/write/{abc_brace_element.js → creation/elements/brace-element.js} +5 -5
  48. package/src/write/creation/elements/free-text.js +41 -0
  49. package/src/write/{abc_relative_element.js → creation/elements/relative-element.js} +8 -7
  50. package/src/write/{separator.js → creation/elements/separator.js} +2 -2
  51. package/src/write/{abc_staff_group_element.js → creation/elements/staff-group-element.js} +4 -4
  52. package/src/write/{subtitle.js → creation/elements/subtitle.js} +3 -3
  53. package/src/write/creation/elements/tempo-element.js +63 -0
  54. package/src/write/{abc_tie_element.js → creation/elements/tie-element.js} +15 -11
  55. package/src/write/{top-text.js → creation/elements/top-text.js} +12 -12
  56. package/src/write/creation/elements/triplet-element.js +28 -0
  57. package/src/write/{abc_voice_element.js → creation/elements/voice-element.js} +3 -3
  58. package/src/write/creation/glyphs.js +226 -0
  59. package/src/write/creation/translate-chord.js +37 -0
  60. package/src/write/draw/absolute.js +5 -5
  61. package/src/write/draw/beam.js +8 -8
  62. package/src/write/draw/brace.js +33 -33
  63. package/src/write/draw/crescendo.js +4 -4
  64. package/src/write/draw/debug-box.js +1 -1
  65. package/src/write/draw/draw.js +7 -7
  66. package/src/write/draw/dynamics.js +2 -2
  67. package/src/write/draw/ending.js +6 -6
  68. package/src/write/draw/glissando.js +17 -17
  69. package/src/write/draw/group-elements.js +51 -51
  70. package/src/write/draw/horizontal-line.js +9 -9
  71. package/src/write/draw/non-music.js +1 -1
  72. package/src/write/draw/print-line.js +15 -16
  73. package/src/write/draw/print-stem.js +5 -5
  74. package/src/write/draw/print-symbol.js +12 -12
  75. package/src/write/draw/print-vertical-line.js +8 -8
  76. package/src/write/draw/relative.js +17 -16
  77. package/src/write/draw/selectables.js +5 -5
  78. package/src/write/draw/separator.js +4 -4
  79. package/src/write/draw/set-paper-size.js +2 -2
  80. package/src/write/draw/sprintf.js +31 -31
  81. package/src/write/draw/staff-group.js +36 -30
  82. package/src/write/draw/staff-line.js +2 -2
  83. package/src/write/draw/staff.js +4 -4
  84. package/src/write/draw/tab-line.js +26 -26
  85. package/src/write/draw/tempo.js +30 -30
  86. package/src/write/draw/text.js +5 -5
  87. package/src/write/draw/tie.js +18 -18
  88. package/src/write/draw/triplet.js +6 -6
  89. package/src/write/draw/voice.js +16 -17
  90. package/src/write/{abc_engraver_controller.js → engraver-controller.js} +58 -51
  91. package/src/write/{classes.js → helpers/classes.js} +6 -6
  92. package/src/write/{get-font-and-attr.js → helpers/get-font-and-attr.js} +9 -7
  93. package/src/write/{get-text-size.js → helpers/get-text-size.js} +5 -5
  94. package/src/write/{set-class.js → helpers/set-class.js} +1 -1
  95. package/src/write/{abc_spacing.js → helpers/spacing.js} +1 -1
  96. package/src/write/{highlight.js → interactive/highlight.js} +1 -1
  97. package/src/write/{selection.js → interactive/selection.js} +27 -27
  98. package/src/write/{unhighlight.js → interactive/unhighlight.js} +1 -1
  99. package/src/write/layout/beam.js +13 -13
  100. package/src/write/layout/get-left-edge-of-staff.js +4 -4
  101. package/src/write/layout/layout.js +74 -74
  102. package/src/write/layout/{setUpperAndLowerElements.js → set-upper-and-lower-elements.js} +8 -8
  103. package/src/write/layout/{staffGroup.js → staff-group.js} +32 -32
  104. package/src/write/layout/triplet.js +4 -4
  105. package/src/write/layout/{VoiceElements.js → voice-elements.js} +23 -23
  106. package/src/write/layout/voice.js +6 -6
  107. package/src/write/{abc_renderer.js → renderer.js} +35 -32
  108. package/src/write/svg.js +35 -35
  109. package/test.js +1 -1
  110. package/types/index.d.ts +99 -22
  111. package/version.js +1 -1
  112. package/src/tablatures/instruments/guitar/guitar-fonts.js +0 -19
  113. package/src/tablatures/instruments/violin/violin-fonts.js +0 -19
  114. package/src/tablatures/transposer.js +0 -110
  115. package/src/write/abc_abstract_engraver.js +0 -1026
  116. package/src/write/abc_beam_element.js +0 -113
  117. package/src/write/abc_create_clef.js +0 -72
  118. package/src/write/abc_create_key_signature.js +0 -33
  119. package/src/write/abc_create_note_head.js +0 -107
  120. package/src/write/abc_create_time_signature.js +0 -55
  121. package/src/write/abc_decoration.js +0 -341
  122. package/src/write/abc_glyphs.js +0 -224
  123. package/src/write/abc_tempo_element.js +0 -63
  124. package/src/write/abc_triplet_element.js +0 -28
  125. package/src/write/add-chord.js +0 -103
  126. package/src/write/format-jazz-chord.js +0 -15
  127. package/src/write/free-text.js +0 -41
  128. /package/src/write/{abc_crescendo_element.js → creation/elements/crescendo-element.js} +0 -0
  129. /package/src/write/{abc_dynamic_decoration.js → creation/elements/dynamic-decoration.js} +0 -0
  130. /package/src/write/{abc_ending_element.js → creation/elements/ending-element.js} +0 -0
  131. /package/src/write/{abc_glissando_element.js → creation/elements/glissando-element.js} +0 -0
  132. /package/src/write/layout/{getBarYAt.js → get-bar-y-at.js} +0 -0
@@ -26,11 +26,13 @@ function CreateSynth() {
26
26
  self.audioBuffers = []; // cache of the buffers so starting play can be fast.
27
27
  self.duration = undefined; // the duration of the tune in seconds.
28
28
  self.isRunning = false; // whether there is currently a sound buffer running.
29
+ // self.options = undefined
29
30
 
30
31
  // Load and cache all needed sounds
31
32
  self.init = function(options) {
32
33
  if (!options)
33
34
  options = {};
35
+ // self.options = options
34
36
  registerAudioContext(options.audioContext); // This works no matter what - if there is already an ac it is a nop; if the context is not passed in, then it creates one.
35
37
  var startTime = activeAudioContext().currentTime;
36
38
  self.debugCallback = options.debugCallback;
@@ -283,6 +285,8 @@ function CreateSynth() {
283
285
  self.stop();
284
286
 
285
287
  var noteMapTracks = createNoteMap(self.flattened);
288
+ // if (self.options.swing)
289
+ // addSwing(noteMapTracks, self.options.swing, self.beatsPerMeasure)
286
290
  if (self.sequenceCallback)
287
291
  self.sequenceCallback(noteMapTracks, self.callbackContext);
288
292
 
@@ -477,6 +481,10 @@ function CreateSynth() {
477
481
  return downloadBuffer(self);
478
482
  };
479
483
 
484
+ self.getAudioBuffer = function() {
485
+ return self.audioBuffers[0];
486
+ };
487
+
480
488
  /////////////// Private functions //////////////
481
489
 
482
490
  self._deviceCapable = function() {
@@ -506,6 +514,39 @@ function CreateSynth() {
506
514
  };
507
515
  }
508
516
  };
517
+
518
+ // // this is a first attempt at adding a little bit of swing to the output, but the algorithm isn't correct.
519
+ // function addSwing(noteMapTracks, swing, beatsPerMeasure) {
520
+ // console.log("addSwing", noteMapTracks, swing, beatsPerMeasure)
521
+ // // Swing should be between -0.9 and 0.9. Make sure the input is between them.
522
+ // // Then that is the percentage to add to the first beat, so a negative number moves the second beat earlier.
523
+ // // A value of zero is the same as no swing at all.
524
+ // // This only works when there are an even number of beats in a measure.
525
+ // if (beatsPerMeasure % 2 !== 0)
526
+ // return;
527
+ // swing = parseFloat(swing)
528
+ // if (isNaN(swing))
529
+ // return
530
+ // if (swing < -0.9)
531
+ // swing = -0.9
532
+ // if (swing > 0.9)
533
+ // swing = 0.9
534
+ // var beatLength = (1 / beatsPerMeasure)*2
535
+ // swing = beatLength * swing
536
+ // for (var t = 0; t < noteMapTracks.length; t++) {
537
+ // var track = noteMapTracks[t];
538
+ // for (var i = 0; i < track.length; i++) {
539
+ // var event = track[i];
540
+ // if (event.start % beatLength) {
541
+ // // This is the off beat
542
+ // event.start += swing;
543
+ // } else {
544
+ // // This is the beat
545
+ // event.end += swing;
546
+ // }
547
+ // }
548
+ // }
549
+ // }
509
550
  }
510
551
 
511
552
  module.exports = CreateSynth;
@@ -0,0 +1,50 @@
1
+ var accidentals = {
2
+ "__": -2,
3
+ "_": -1,
4
+ "_/": -0.5,
5
+ "=": 0,
6
+ "": 0,
7
+ "^/": 0.5,
8
+ "^": 1,
9
+ "^^": 2
10
+ }
11
+
12
+ var notesInOrder = ['C', '-', 'D', '-', 'E', 'F', '-', 'G', '-', 'A', '-', 'B', 'c', '-', 'd', '-', 'e', 'f', '-', 'g', '-', 'a', '-', 'b']
13
+
14
+ function noteToMidi(note) {
15
+ var reg = note.match(/([_^\/]*)([ABCDEFGabcdefg])(,*)('*)/)
16
+ if (reg && reg.length === 5) {
17
+ var acc = accidentals[reg[1]]
18
+ var pitch = notesInOrder.indexOf(reg[2])
19
+ var octave = reg[4].length - reg[3].length
20
+ return 48 + pitch + acc + octave * 12;
21
+ }
22
+ return 0;
23
+ }
24
+
25
+ function midiToNote(midi) {
26
+ midi = parseInt(midi, 10) // TODO-PER: not sure how to handle quarter sharps and flats, so strip them for now.
27
+ var octave = Math.floor(midi / 12)
28
+ var pitch = midi % 12
29
+ var name = notesInOrder[pitch]
30
+ if (name === '-') {
31
+ name = '^' + notesInOrder[pitch-1]
32
+ }
33
+
34
+ if (octave > 4) {
35
+ name = name.toLowerCase()
36
+ octave -= 5
37
+ while (octave > 0) {
38
+ name += "'"
39
+ octave--
40
+ }
41
+ } else {
42
+ while (octave < 4) {
43
+ name += ','
44
+ octave++
45
+ }
46
+ }
47
+ return name
48
+ }
49
+
50
+ module.exports = {noteToMidi: noteToMidi, midiToNote: midiToNote};
@@ -5,7 +5,6 @@ var StringTablature = require('../string-tablature');
5
5
  var TabCommon = require('../../tab-common');
6
6
  var TabRenderer = require('../../tab-renderer');
7
7
  var GuitarPatterns = require('./guitar-patterns');
8
- var setGuitarFonts = require('./guitar-fonts');
9
8
 
10
9
  /**
11
10
  * upon init mainly store provided instances for later usage
@@ -32,7 +31,6 @@ Plugin.prototype.init = function (abcTune, tuneNumber, params) {
32
31
  Plugin.prototype.render = function (renderer, line, staffIndex) {
33
32
  if (this._super.inError) return;
34
33
  if (this.tablature.bypass(line)) return;
35
- setGuitarFonts(this.abcTune);
36
34
  var rndrer = new TabRenderer(this, renderer, line, staffIndex);
37
35
  rndrer.doLayout();
38
36
  };
@@ -1,3 +1,4 @@
1
+ const {noteToMidi} = require('../../synth/note-to-midi');
1
2
  var TabNote = require('./tab-note');
2
3
  var TabNotes = require('./tab-notes');
3
4
 
@@ -93,7 +94,10 @@ function sameString(self, chord) {
93
94
  function handleChordNotes(self, notes) {
94
95
  var retNotes = [];
95
96
  for (var iiii = 0; iiii < notes.length; iiii++) {
96
- var note = new TabNote.TabNote(notes[iiii].name);
97
+ if (notes[iiii].endTie)
98
+ continue;
99
+ var note = new TabNote.TabNote(notes[iiii].name, self.clefTranspose);
100
+ note.checkKeyAccidentals(self.accidentals, self.measureAccidentals)
97
101
  var curPos = toNumber(self, note);
98
102
  retNotes.push(curPos);
99
103
  }
@@ -147,26 +151,23 @@ function toNumber(self, note) {
147
151
  acc = "="
148
152
  self.measureAccidentals[note.name.toUpperCase()] = acc
149
153
  }
150
- var num = null;
151
- var str = 0;
152
- var lowestString = self.strings[self.strings.length - 1];
153
- var lowestNote = new TabNote.TabNote(lowestString[0]);
154
- if (note.isLowerThan(lowestNote) ) {
155
- return {
156
- num: "?",
157
- str: self.strings.length - 1,
158
- note: note,
159
- error: note.emit() + ': unexpected note for instrument'
160
- };
161
- }
162
- while (str < self.strings.length) {
163
- num = noteToNumber(self, note, str);
164
- if (num) {
165
- return num;
154
+ for (var i = self.stringPitches.length-1; i >= 0; i--) {
155
+ if (note.pitch + note.pitchAltered >= self.stringPitches[i]) {
156
+ var num = note.pitch + note.pitchAltered - self.stringPitches[i]
157
+ if (note.quarter === '^') num -= 0.5
158
+ else if (note.quarter === "v") num += 0.5
159
+ return {
160
+ num: Math.round(num),
161
+ str: self.stringPitches.length-1-i, // reverse the strings because string 0 is on the bottom
162
+ note: note
163
+ }
166
164
  }
167
- str++;
168
165
  }
169
- return null; // not found
166
+ return {
167
+ num: "?",
168
+ str: self.stringPitches.length-1,
169
+ note: note,
170
+ };
170
171
  }
171
172
 
172
173
  StringPatterns.prototype.stringToPitch = function (stringNumber) {
@@ -198,13 +199,16 @@ StringPatterns.prototype.notesToNumber = function (notes, graces) {
198
199
  error = retNotes.error;
199
200
  }
200
201
  } else {
201
- note = new TabNote.TabNote(notes[0].name);
202
- number = toNumber(this, note);
203
- if (number) {
204
- retNotes.push(number);
205
- } else {
206
- invalidNumber(retNotes, note);
207
- error = retNotes.error;
202
+ if (!notes[0].endTie) {
203
+ note = new TabNote.TabNote(notes[0].name, this.clefTranspose);
204
+ note.checkKeyAccidentals(this.accidentals, this.measureAccidentals)
205
+ number = toNumber(this, note);
206
+ if (number) {
207
+ retNotes.push(number);
208
+ } else {
209
+ invalidNumber(retNotes, note);
210
+ error = retNotes.error;
211
+ }
208
212
  }
209
213
  }
210
214
  }
@@ -213,7 +217,8 @@ StringPatterns.prototype.notesToNumber = function (notes, graces) {
213
217
  if (graces) {
214
218
  retGraces = [];
215
219
  for (var iiii = 0; iiii < graces.length; iiii++) {
216
- note = new TabNote.TabNote(graces[iiii].name);
220
+ note = new TabNote.TabNote(graces[iiii].name, this.clefTranspose);
221
+ note.checkKeyAccidentals(this.accidentals, this.measureAccidentals)
217
222
  number = toNumber(this, note);
218
223
  if (number) {
219
224
  retGraces.push(number);
@@ -232,7 +237,14 @@ StringPatterns.prototype.notesToNumber = function (notes, graces) {
232
237
  };
233
238
 
234
239
  StringPatterns.prototype.toString = function () {
235
- return this.tuning.join('').replaceAll(',', '').toUpperCase();
240
+ var arr = []
241
+ for (var i = 0; i < this.tuning.length; i++) {
242
+ var str = this.tuning[i].replaceAll(',', '').replaceAll("'", '').toUpperCase();
243
+ if (str[0] === '_') str = str[1] + 'b '
244
+ else if (str[0] === '^') str = str[1] + "# "
245
+ arr.push(str)
246
+ }
247
+ return arr.join('');
236
248
  };
237
249
 
238
250
  StringPatterns.prototype.tabInfos = function (plugin) {
@@ -275,7 +287,13 @@ function StringPatterns(plugin) {
275
287
  if (capo) {
276
288
  this.capo = capo;
277
289
  }
290
+ this.transpose = plugin.transpose ? plugin.transpose : 0
278
291
  this.tuning = tuning;
292
+ this.stringPitches = []
293
+ for (var i = 0; i < this.tuning.length; i++) {
294
+ var pitch = noteToMidi(this.tuning[i]) + this.capo
295
+ this.stringPitches.push(pitch)
296
+ }
279
297
  if (this.capo > 0) {
280
298
  this.capoTuning = buildCapo(this);
281
299
  }
@@ -1,3 +1,5 @@
1
+ var {noteToMidi, midiToNote} = require('../../synth/note-to-midi');
2
+
1
3
  /**
2
4
  *
3
5
  * Note structure for Tabs
@@ -6,9 +8,12 @@
6
8
  var notes = ['A', 'B', 'C', 'D', 'E', 'F', 'G'];
7
9
 
8
10
 
9
- function TabNote(note) {
11
+ function TabNote(note, clefTranspose) {
12
+ var pitch = noteToMidi(note)
13
+ if (clefTranspose)
14
+ pitch += clefTranspose
15
+ var newNote = midiToNote(pitch);
10
16
  var isFlat = false;
11
- var newNote = note;
12
17
  var isSharp = false;
13
18
  var isAltered = false;
14
19
  var natural = null;
@@ -54,9 +59,11 @@ function TabNote(note) {
54
59
  newNote = note.slice(1);
55
60
  }
56
61
  }
57
- var hasComma = (note.match(/,/g) || []).length;
58
- var hasQuote = (note.match(/'/g) || []).length;
62
+ var hasComma = (newNote.match(/,/g) || []).length;
63
+ var hasQuote = (newNote.match(/'/g) || []).length;
59
64
 
65
+ this.pitch = pitch
66
+ this.pitchAltered = 0
60
67
  this.name = newNote;
61
68
  this.acc = acc;
62
69
  this.isSharp = isSharp;
@@ -76,6 +83,7 @@ function TabNote(note) {
76
83
  function cloneNote(self) {
77
84
  var newNote = self.name;
78
85
  var newTabNote = new TabNote(newNote);
86
+ newTabNote.pitch = self.pitch;
79
87
  newTabNote.hasComma = self.hasComma;
80
88
  newTabNote.isLower = self.isLower;
81
89
  newTabNote.isQuoted = self.isQuoted;
@@ -86,33 +94,11 @@ function cloneNote(self) {
86
94
  return newTabNote;
87
95
  }
88
96
  TabNote.prototype.sameNoteAs = function (note) {
89
- if ((this.name == note.name) &&
90
- (this.hasComma == note.hasComma) &&
91
- (this.isLower == note.isLower) &&
92
- (this.isQuoted == note.isQuoted) &&
93
- (this.isSharp == note.isSharp) &&
94
- (this.isFlat == note.isFlat)) {
95
- return true;
96
- } else {
97
- return false;
98
- }
97
+ return note.pitch === this.pitch
99
98
  };
100
99
 
101
100
  TabNote.prototype.isLowerThan = function (note) {
102
- var noteComparator = ['C','D','E','F','G','A','B'];
103
- if (this.hasComma > note.hasComma) return true;
104
- if (note.hasComma > this.hasComma) return false;
105
- if (this.isQuoted > note.isQuoted) return false;
106
- if (note.isQuoted > this.isQuoted) return true;
107
- if (this.isLower) {
108
- if (!note.isLower) return false;
109
- } else {
110
- if (note.isLower) return true;
111
- }
112
- var noteName = note.name[0].toUpperCase();
113
- var thisName = this.name[0].toUpperCase();
114
- if (noteComparator.indexOf(thisName) < noteComparator.indexOf(noteName)) return true;
115
- return false;
101
+ return note.pitch > this.pitch
116
102
  };
117
103
 
118
104
  TabNote.prototype.checkKeyAccidentals = function(accidentals, measureAccidentals) {
@@ -120,14 +106,13 @@ TabNote.prototype.checkKeyAccidentals = function(accidentals, measureAccidentals
120
106
  return
121
107
  if (measureAccidentals[this.name.toUpperCase()]) {
122
108
  switch (measureAccidentals[this.name.toUpperCase()]) {
123
- case "__": this.acc = -2; return;
124
- case "_": this.acc = -1; return;
125
- case "=": this.acc = 0; return;
126
- case "^": this.acc = 1; return;
127
- case "^^": this.acc = 2; return;
109
+ case "__": this.acc = -2; this.pitchAltered = -2; return;
110
+ case "_": this.acc = -1; this.pitchAltered = -1; return;
111
+ case "=": this.acc = 0; this.pitchAltered = 0; return;
112
+ case "^": this.acc = 1; this.pitchAltered = 1; return;
113
+ case "^^": this.acc = 2; this.pitchAltered = 2; return;
128
114
  }
129
- }
130
- if (accidentals) {
115
+ } else if (accidentals) {
131
116
  var curNote = this.name;
132
117
  for (var iii = 0; iii < accidentals.length; iii++) {
133
118
  var curAccidentals = accidentals[iii];
@@ -135,10 +120,12 @@ TabNote.prototype.checkKeyAccidentals = function(accidentals, measureAccidentals
135
120
  if (curAccidentals.acc == 'flat') {
136
121
  this.acc = -1;
137
122
  this.isKeyFlat = true;
123
+ this.pitchAltered = -1
138
124
  }
139
125
  if (curAccidentals.acc == 'sharp') {
140
126
  this.acc = +1;
141
127
  this.isKeySharp = true;
128
+ this.pitchAltered = 1
142
129
  }
143
130
  }
144
131
  }
@@ -163,77 +150,13 @@ TabNote.prototype.getAccidentalEquiv = function () {
163
150
 
164
151
 
165
152
  TabNote.prototype.nextNote = function () {
166
- var newTabNote = cloneNote(this);
167
-
168
- if (!this.isSharp && !this.isKeySharp ) {
169
- if (this.name != 'E' && this.name != 'B') {
170
- newTabNote.isSharp = true;
171
- return newTabNote;
172
- }
173
- } else {
174
- // cleanup
175
- newTabNote.isSharp = false;
176
- newTabNote.isKeySharp = false;
177
- }
178
- var noteIndex = notes.indexOf(this.name);
179
- if (noteIndex == notes.length - 1) {
180
- noteIndex = 0;
181
- } else {
182
- noteIndex++;
183
- }
184
- newTabNote.name = notes[noteIndex];
185
- if (newTabNote.name == 'C') {
186
- if (newTabNote.hasComma > 0) {
187
- newTabNote.hasComma--;
188
- } else {
189
- if (!newTabNote.isLower) {
190
- newTabNote.isLower = true;
191
- } else {
192
- newTabNote.isQuoted = true;
193
- }
194
- }
195
- }
196
- return newTabNote;
153
+ var note = midiToNote(this.pitch+1+this.pitchAltered)
154
+ return new TabNote(note)
197
155
  };
198
156
 
199
157
  TabNote.prototype.prevNote = function () {
200
- var newTabNote = cloneNote(this);
201
-
202
- if (this.isSharp) {
203
- newTabNote.isSharp = false;
204
- return newTabNote;
205
- }
206
- var noteIndex = notes.indexOf(this.name);
207
- if (noteIndex == 0) {
208
- noteIndex = notes.length - 1;
209
- } else {
210
- noteIndex--;
211
- }
212
- newTabNote.name = notes[noteIndex];
213
- if (newTabNote.name == 'B') {
214
- if (newTabNote.isLower) {
215
- newTabNote.hasComma = 1;
216
- } else {
217
- if (newTabNote.hasComma > 0) {
218
- newTabNote.hasComma++;
219
- } else {
220
- if (newTabNote.isQuoted > 0) {
221
- newTabNote.isQuoted -= 1;
222
- } else {
223
- newTabNote.isLower = true;
224
- }
225
- }
226
- }
227
- }
228
- if (this.isFlat) {
229
- newTabNote.isFlat = false;
230
- return newTabNote;
231
- } else {
232
- if (this.name != 'E' && this.name != 'B') {
233
- newTabNote.isSharp = true;
234
- }
235
- }
236
- return newTabNote;
158
+ var note = midiToNote(this.pitch-1+this.pitchAltered)
159
+ return new TabNote(note)
237
160
  };
238
161
 
239
162
  TabNote.prototype.emitNoAccidentals = function ( ) {
@@ -3,7 +3,6 @@ var StringTablature = require('../string-tablature');
3
3
  var TabCommon = require('../../tab-common');
4
4
  var TabRenderer = require('../../tab-renderer');
5
5
  var ViolinPatterns = require('./violin-patterns');
6
- var setViolinFonts = require('./violin-fonts');
7
6
 
8
7
 
9
8
  /**
@@ -30,7 +29,6 @@ Plugin.prototype.init = function (abcTune, tuneNumber, params) {
30
29
  Plugin.prototype.render = function (renderer, line, staffIndex) {
31
30
  if (this._super.inError) return;
32
31
  if (this.tablature.bypass(line)) return;
33
- setViolinFonts(this.abcTune);
34
32
  var rndrer = new TabRenderer(this, renderer, line, staffIndex);
35
33
  rndrer.doLayout();
36
34
  };
@@ -1,9 +1,8 @@
1
1
  /**
2
2
  * Tablature Absolute elements factory
3
3
  */
4
- var AbsoluteElement = require('../write/abc_absolute_element');
5
- var RelativeElement = require('../write/abc_relative_element');
6
- var Transposer = require('./transposer');
4
+ var AbsoluteElement = require('../write/creation/elements/absolute-element');
5
+ var RelativeElement = require('../write/creation/elements/relative-element');
7
6
 
8
7
  function isObject(a) { return a != null && a.constructor === Object; }
9
8
  function cloneObject(dest, src) {
@@ -144,20 +143,6 @@ function graceInRest( absElem ) {
144
143
  return null;
145
144
  }
146
145
 
147
- function checkTransposition(plugin, transposer ,pitches, graceNotes) {
148
- if (plugin.transpose) {
149
- //transposer.transpose(plugin.transpose);
150
- for (var jj = 0; jj < pitches.length; jj++) {
151
- pitches[jj] = transposer.transposeNote(pitches[jj]);
152
- }
153
- if (graceNotes) {
154
- for (var kk = 0; kk < graceNotes.length; kk++) {
155
- graceNotes[kk] = transposer.transposeNote(graceNotes[kk]);
156
- }
157
- }
158
- }
159
- }
160
-
161
146
  function convertToNumber(plugin, pitches, graceNotes) {
162
147
  var tabPos = plugin.semantics.notesToNumber(pitches, graceNotes);
163
148
  if (tabPos.error) {
@@ -196,7 +181,6 @@ TabAbsoluteElements.prototype.build = function (plugin,
196
181
  var staffSize = getInitialStaffSize(staffAbsolute);
197
182
  var source = staffAbsolute[staffIndex+voiceIndex];
198
183
  var dest = staffAbsolute[staffSize+staffIndex+voiceIndex];
199
- var transposer = null;
200
184
  var tabPos = null;
201
185
  var defNote = null;
202
186
  if (source.children[0].abcelem.el_type != 'clef') {
@@ -214,18 +198,14 @@ TabAbsoluteElements.prototype.build = function (plugin,
214
198
  // }
215
199
  if ( (absChild.isClef) ) {
216
200
  dest.children.push(buildTabAbsolute(plugin, absX, relX));
201
+ if (absChild.abcelem.type.indexOf('-8') >= 0) plugin.semantics.strings.clefTranspose = -12
202
+ if (absChild.abcelem.type.indexOf('+8') >= 0) plugin.semantics.strings.clefTranspose = 12
217
203
  }
218
204
  switch (absChild.type) {
219
205
  case 'staff-extra key-signature':
220
206
  // refresh key accidentals
221
207
  this.accidentals = absChild.abcelem.accidentals;
222
208
  plugin.semantics.strings.accidentals = this.accidentals;
223
- if (plugin.transpose) {
224
- transposer = new Transposer(
225
- absChild.abcelem.accidentals,
226
- plugin.transpose
227
- );
228
- }
229
209
  break;
230
210
  case 'bar':
231
211
  plugin.semantics.strings.measureAccidentals = {}
@@ -258,8 +238,6 @@ TabAbsoluteElements.prototype.build = function (plugin,
258
238
  case 'rest':
259
239
  var restGraces = graceInRest(absChild);
260
240
  if (restGraces) {
261
- // check transpose
262
- checkTransposition(plugin, transposer, null, restGraces);
263
241
  // to number conversion
264
242
  tabPos = convertToNumber(plugin, null, restGraces);
265
243
  if (tabPos.error) return;
@@ -274,9 +252,7 @@ TabAbsoluteElements.prototype.build = function (plugin,
274
252
  abs.lyricDim = lyricsDim(absChild);
275
253
  var pitches = absChild.abcelem.pitches;
276
254
  var graceNotes = absChild.abcelem.gracenotes;
277
- // check transpose
278
255
  abs.type = 'tabNumber';
279
- checkTransposition(plugin, transposer, pitches, graceNotes);
280
256
  // to number conversion
281
257
  tabPos = convertToNumber(plugin, pitches, graceNotes);
282
258
  if (tabPos.error) return;
@@ -302,9 +278,11 @@ TabAbsoluteElements.prototype.build = function (plugin,
302
278
  var tabNoteRelative = buildRelativeTabNote(plugin, abs.x+absChild.heads[ll].dx, defNote, curNote, false);
303
279
  abs.children.push(tabNoteRelative);
304
280
  }
305
- defNote.abselem = abs;
306
- tabVoice.push(defNote);
307
- dest.children.push(abs);
281
+ if (defNote.notes.length > 0) {
282
+ defNote.abselem = abs;
283
+ tabVoice.push(defNote);
284
+ dest.children.push(abs);
285
+ }
308
286
  break;
309
287
  }
310
288
  }
@@ -1,7 +1,7 @@
1
1
  /* eslint-disable no-debugger */
2
- var VoiceElement = require('../write/abc_voice_element');
2
+ var VoiceElement = require('../write/creation/elements/voice-element');
3
3
  var TabAbsoluteElements = require('./tab-absolute-elements');
4
- var spacing = require('../write/abc_spacing');
4
+ var spacing = require('../write/helpers/spacing');
5
5
 
6
6
  function initSpecialY() {
7
7
  return {
@@ -61,7 +61,7 @@ var ParserLint = function() {
61
61
  "p", "pp", "f", "ff", "mf", "mp", "ppp", "pppp", "fff", "ffff", "sfz", "repeatbar", "repeatbar2", "slide",
62
62
  "upbow", "downbow", "staccato", "trem1", "trem2", "trem3", "trem4",
63
63
  "/", "//", "///", "////", "turnx", "invertedturn", "invertedturnx", "arpeggio", "trill(", "trill)", "xstem",
64
- "mark", "marcato", "umarcato"
64
+ "mark", "marcato", "umarcato", "D.C.alcoda", "D.C.alfine", "D.S.alcoda", "D.S.alfine", "editorial", "courtesy"
65
65
  ] } };
66
66
 
67
67
  var tempoProperties = {
@@ -318,7 +318,7 @@ var ParserLint = function() {
318
318
  var midiProperties = {
319
319
  cmd: { type: 'string', Enum: [
320
320
  "nobarlines", "barlines", "beataccents", "nobeataccents", "droneon", "droneoff", "noportamento", "channel", "c",
321
- "drumon", "drumoff", "fermatafixed", "fermataproportional", "gchordon", "gchordoff", "bassvol", "chordvol",
321
+ "drumon", "drumoff", "fermatafixed", "fermataproportional", "gchordon", "gchordoff", "bassvol", "chordvol", "bassprog", "chordprog",
322
322
  "controlcombo", "temperamentnormal", "gchord", "ptstress", "beatmod", "deltaloudness", "drumbars", "pitchbend",
323
323
  "gracedivider", "makechordchannels", "randomchordattack", "chordattack", "stressmodel", "transpose",
324
324
  "rtranspose", "volinc", "program", "ratio", "snt", "bendvelocity", "control", "temperamentlinear", "beat", "beatstring",
@@ -335,6 +335,7 @@ var ParserLint = function() {
335
335
  field: "el_type",
336
336
  types: [
337
337
  { value: "clef", properties: appendPositioning(clefProperties) },
338
+ { value: "color", properties: { color: {type: "string", optional: true } } },
338
339
  { value: "bar", properties: prependPositioning(barProperties) },
339
340
  { value: "gap", properties: { type: "number", optional: true } }, // staffbreak
340
341
  { value: "key", properties: appendPositioning(keyProperties) },
@@ -462,9 +463,11 @@ var ParserLint = function() {
462
463
  infospace: { type: "number", optional: true },
463
464
  // landscape: { type: "boolean", optional: true },
464
465
  jazzchords: { type: "boolean", optional: true },
466
+ germanAlphabet: { type: "boolean", optional: true },
465
467
  leftmargin: { type: "number", optional: true },
466
468
  linesep: { type: "number", optional: true },
467
469
  lineskipfac: { type: "number", optional: true },
470
+ lineThickness: { type: "number", optional: true },
468
471
  map: { type: "string", optional: true },
469
472
  maxshrink: { type: "number", optional: true },
470
473
  maxstaffsep: { type: "number", optional: true },
@@ -741,14 +744,14 @@ var ParserLint = function() {
741
744
  this.lint = function(tune, warnings) {
742
745
  var ret = JSONSchema.validate(tune, musicSchema);
743
746
  var err = "";
744
- parseCommon.each(ret.errors, function(e) {
747
+ ret.errors.forEach(function(e) {
745
748
  err += e.property + ": " + e.message + "\n";
746
749
  });
747
750
  var out = ret.output.join("\n");
748
751
 
749
752
  var warn = warnings === undefined ? "No errors" : warnings.join('\n');
750
- warn = parseCommon.gsub(warn, '<span style="text-decoration:underline;font-size:1.3em;font-weight:bold;">', '$$$$');
751
- warn = parseCommon.gsub(warn, '</span>', '$$$$');
753
+ warn = warn.replace(/<span style="text-decoration:underline;font-size:1.3em;font-weight:bold;">/g, '$$$$$$$$');
754
+ warn = warn.replace(/<\/span>/g, '$$$$$$$$');
752
755
  return "Error:------\n" + err + "\nObj:-------\n" + out + "\nWarn:------\n" + warn;
753
756
  };
754
757
  };
@@ -0,0 +1,31 @@
1
+ # Architecture of the engraver
2
+
3
+ The engraver code is handled here. This accepts the output of the parser and does three things:
4
+
5
+ * Creates an SVG
6
+ * Adds data to the parser input
7
+ * Makes the visual elements interactive
8
+
9
+ ## Steps
10
+
11
+ There are separate passes and sub-passes to the processing. The separate passes match the subfolder organization here.
12
+
13
+ They are:
14
+
15
+ ### Element Creation
16
+
17
+ The structure passed in from the parser is traversed and all elements are created. An element consists of two parts:
18
+
19
+ * The Absolute Element: a visual piece of music that is always moved together. For instance, in the key signature of D, the absolute element is an object that contains two sharp symbols. The absolute element has an X- and Y- position in the SVG, and an array of Relative Elements.
20
+
21
+ * Relative Element: These are always attached to an absolute element. They have a relative position to the absolute element and consist of all the glyphs needed. For instance, a dotted eighth note of Bb that is trilled is an absolute element that contains an array of relative elements consisting of a trill, a flat sign, a filled note head, a stem, a flag, and a dot.
22
+
23
+ Each of these elements is a separate object, created with `new` and placed in the structure passed in from the parser.
24
+
25
+ ### Layout
26
+
27
+ After all the elements are created the size of all of them are known, so the layout process begins. There are separate layout algorithms for the horizontal and the vertical positioning.
28
+
29
+ ### Drawing
30
+
31
+ After the layout is finished, it is a rote process to draw the music. All decisions have been made. The structure is then traversed and each element is created in the SVG.