abcjs-rails 2.3 → 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 (33) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/javascripts/abcjs/api/abc_animation.js +166 -4
  3. data/app/assets/javascripts/abcjs/api/abc_tunebook.js +170 -15
  4. data/app/assets/javascripts/abcjs/data/abc_tune.js +69 -47
  5. data/app/assets/javascripts/abcjs/edit/abc_editor.js +78 -37
  6. data/app/assets/javascripts/abcjs/midi/abc_midi_controls.js +513 -0
  7. data/app/assets/javascripts/abcjs/midi/abc_midi_create.js +29 -7
  8. data/app/assets/javascripts/abcjs/midi/abc_midi_flattener.js +21 -18
  9. data/app/assets/javascripts/abcjs/midi/abc_midi_js_preparer.js +233 -0
  10. data/app/assets/javascripts/abcjs/midi/abc_midi_renderer.js +3 -229
  11. data/app/assets/javascripts/abcjs/midi/abc_midi_sequencer.js +11 -3
  12. data/app/assets/javascripts/abcjs/parse/abc_common.js +24 -0
  13. data/app/assets/javascripts/abcjs/parse/abc_parse.js +58 -16
  14. data/app/assets/javascripts/abcjs/parse/abc_parse_header.js +4 -1
  15. data/app/assets/javascripts/abcjs/parse/abc_parse_key_voice.js +5 -0
  16. data/app/assets/javascripts/abcjs/write/abc_absolute_element.js +9 -2
  17. data/app/assets/javascripts/abcjs/write/abc_abstract_engraver.js +71 -19
  18. data/app/assets/javascripts/abcjs/write/abc_beam_element.js +11 -3
  19. data/app/assets/javascripts/abcjs/write/abc_brace_element.js +51 -0
  20. data/app/assets/javascripts/abcjs/write/abc_create_clef.js +3 -3
  21. data/app/assets/javascripts/abcjs/write/abc_create_key_signature.js +3 -3
  22. data/app/assets/javascripts/abcjs/write/abc_create_time_signature.js +3 -3
  23. data/app/assets/javascripts/abcjs/write/abc_crescendo_element.js +4 -1
  24. data/app/assets/javascripts/abcjs/write/abc_decoration.js +1 -1
  25. data/app/assets/javascripts/abcjs/write/abc_engraver_controller.js +10 -9
  26. data/app/assets/javascripts/abcjs/write/abc_glyphs.js +1 -1
  27. data/app/assets/javascripts/abcjs/write/abc_relative_element.js +1 -1
  28. data/app/assets/javascripts/abcjs/write/abc_renderer.js +85 -13
  29. data/app/assets/javascripts/abcjs/write/abc_staff_group_element.js +16 -0
  30. data/app/assets/javascripts/abcjs/write/abc_tempo_element.js +31 -11
  31. data/app/assets/javascripts/abcjs/write/abc_tie_element.js +8 -1
  32. data/lib/abcjs-rails/version.rb +1 -1
  33. metadata +6 -3
@@ -53,6 +53,10 @@ if (!window.ABCJS.write)
53
53
  this.beams = []; // During the layout phase, this will become a list of the beams that need to be drawn.
54
54
  };
55
55
 
56
+ ABCJS.write.BeamElem.prototype.setHint = function () {
57
+ this.hint = true;
58
+ };
59
+
56
60
  ABCJS.write.BeamElem.prototype.add = function(abselem) {
57
61
  var pitch = abselem.abcelem.averagepitch;
58
62
  if (pitch === undefined) return; // don't include elements like spacers in beams
@@ -134,7 +138,7 @@ if (!window.ABCJS.write)
134
138
  renderer.beginGroup();
135
139
  for (var i = 0; i < this.beams.length; i++) {
136
140
  var beam = this.beams[i];
137
- drawBeam(renderer, beam.startX, beam.startY, beam.endX, beam.endY, beam.dy);
141
+ drawBeam(renderer, beam.startX, beam.startY, beam.endX, beam.endY, beam.dy, this.hint);
138
142
  }
139
143
  renderer.endGroup('beam-elem');
140
144
  };
@@ -169,7 +173,11 @@ if (!window.ABCJS.write)
169
173
  return dy;
170
174
  }
171
175
 
172
- function drawBeam(renderer, startX, startY, endX, endY, dy) {
176
+ function drawBeam(renderer, startX, startY, endX, endY, dy, isHint) {
177
+ var klass = 'beam-elem';
178
+ if (isHint)
179
+ klass += " abcjs-hint";
180
+
173
181
  // the X coordinates are actual coordinates, but the Y coordinates are in pitches.
174
182
  startY = renderer.calcY(startY);
175
183
  endY = renderer.calcY(endY);
@@ -179,7 +187,7 @@ if (!window.ABCJS.write)
179
187
  path: pathString,
180
188
  stroke: "none",
181
189
  fill: "#000000",
182
- 'class': renderer.addClasses('beam-elem')
190
+ 'class': renderer.addClasses(klass)
183
191
  });
184
192
  }
185
193
 
@@ -0,0 +1,51 @@
1
+ // abc_brace_element.js: Definition of the BraceElement class.
2
+ // Copyright (C) 2010,2016 Gregory Dyke (gregdyke at gmail dot com) and Paul Rosen
3
+ //
4
+ // This program is free software: you can redistribute it and/or modify
5
+ // it under the terms of the GNU General Public License as published by
6
+ // the Free Software Foundation, either version 3 of the License, or
7
+ // (at your option) any later version.
8
+ //
9
+ // This program is distributed in the hope that it will be useful,
10
+ // but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ // GNU General Public License for more details.
13
+ //
14
+ // You should have received a copy of the GNU General Public License
15
+ // along with this program. If not, see <http://www.gnu.org/licenses/>.
16
+
17
+ /*globals ABCJS */
18
+
19
+ if (!window.ABCJS)
20
+ window.ABCJS = {};
21
+
22
+
23
+ if (!window.ABCJS.write)
24
+ window.ABCJS.write = {};
25
+
26
+ ABCJS.write.BraceElem = function() {
27
+ this.length = 1;
28
+ };
29
+
30
+ ABCJS.write.BraceElem.prototype.increaseStavesIncluded = function() {
31
+ this.length++;
32
+ };
33
+
34
+ ABCJS.write.BraceElem.prototype.setLocation = function(x) {
35
+ this.x = x;
36
+ };
37
+
38
+ ABCJS.write.BraceElem.prototype.getWidth = function() {
39
+ return 10; // TODO-PER: right now the drawing function doesn't vary the width at all. If it does in the future then this will change.
40
+ };
41
+
42
+ ABCJS.write.BraceElem.prototype.layout = function (renderer, top, bottom) {
43
+ this.startY = top;
44
+ this.endY = bottom;
45
+ };
46
+
47
+ ABCJS.write.BraceElem.prototype.draw = function (renderer, top, bottom) {
48
+ this.layout(renderer, top, bottom);
49
+ renderer.drawBrace(this.x,this.startY, this.endY);
50
+
51
+ };
@@ -1,5 +1,5 @@
1
1
  // abc_create_clef.js
2
- // Copyright (C) 2010,2015 Gregory Dyke (gregdyke at gmail dot com) and Paul Rosen
2
+ // Copyright (C) 2010,2016 Gregory Dyke (gregdyke at gmail dot com) and Paul Rosen
3
3
  //
4
4
  // This program is free software: you can redistribute it and/or modify
5
5
  // it under the terms of the GNU General Public License as published by
@@ -25,10 +25,10 @@ if (!window.ABCJS.write)
25
25
  (function() {
26
26
  "use strict";
27
27
 
28
- ABCJS.write.createClef = function(elem) {
28
+ ABCJS.write.createClef = function(elem, tuneNumber) {
29
29
  var clef;
30
30
  var octave = 0;
31
- var abselem = new ABCJS.write.AbsoluteElement(elem,0,10, 'staff-extra');
31
+ var abselem = new ABCJS.write.AbsoluteElement(elem,0,10, 'staff-extra', tuneNumber);
32
32
  switch (elem.type) {
33
33
  case "treble": clef = "clefs.G"; break;
34
34
  case "tenor": clef="clefs.C"; break;
@@ -1,5 +1,5 @@
1
1
  // abc_create_key_signature.js
2
- // Copyright (C) 2010,2015 Gregory Dyke (gregdyke at gmail dot com) and Paul Rosen
2
+ // Copyright (C) 2010,2016 Gregory Dyke (gregdyke at gmail dot com) and Paul Rosen
3
3
  //
4
4
  // This program is free software: you can redistribute it and/or modify
5
5
  // it under the terms of the GNU General Public License as published by
@@ -25,10 +25,10 @@ if (!window.ABCJS.write)
25
25
  (function() {
26
26
  "use strict";
27
27
 
28
- ABCJS.write.createKeySignature = function(elem) {
28
+ ABCJS.write.createKeySignature = function(elem, tuneNumber) {
29
29
  if (!elem.accidentals || elem.accidentals.length === 0)
30
30
  return null;
31
- var abselem = new ABCJS.write.AbsoluteElement(elem, 0, 10, 'staff-extra');
31
+ var abselem = new ABCJS.write.AbsoluteElement(elem, 0, 10, 'staff-extra', tuneNumber);
32
32
  var dx = 0;
33
33
  window.ABCJS.parse.each(elem.accidentals, function(acc) {
34
34
  var symbol = (acc.acc === "sharp") ? "accidentals.sharp" : (acc.acc === "natural") ? "accidentals.nat" : "accidentals.flat";
@@ -1,5 +1,5 @@
1
1
  // abc_create_time_signature.js
2
- // Copyright (C) 2010,2015 Gregory Dyke (gregdyke at gmail dot com) and Paul Rosen
2
+ // Copyright (C) 2010,2016 Gregory Dyke (gregdyke at gmail dot com) and Paul Rosen
3
3
  //
4
4
  // This program is free software: you can redistribute it and/or modify
5
5
  // it under the terms of the GNU General Public License as published by
@@ -25,8 +25,8 @@ if (!window.ABCJS.write)
25
25
  (function() {
26
26
  "use strict";
27
27
 
28
- ABCJS.write.createTimeSignature = function(elem) {
29
- var abselem = new ABCJS.write.AbsoluteElement(elem,0,10, 'staff-extra');
28
+ ABCJS.write.createTimeSignature = function(elem, tuneNumber) {
29
+ var abselem = new ABCJS.write.AbsoluteElement(elem,0,10, 'staff-extra', tuneNumber);
30
30
  if (elem.type === "specified") {
31
31
  //TODO make the alignment for time signatures centered
32
32
  for (var i = 0; i < elem.value.length; i++) {
@@ -55,7 +55,10 @@ ABCJS.write.CrescendoElem.prototype.draw = function (renderer) {
55
55
  };
56
56
 
57
57
  ABCJS.write.CrescendoElem.prototype.drawLine = function (renderer, y1, y2) {
58
+ // TODO-PER: This is just a quick hack to make the dynamic marks not crash if they are mismatched. See the slur treatment for the way to get the beginning and end.
59
+ var left = this.anchor1 ? this.anchor1.x : 0;
60
+ var right = this.anchor2 ? this.anchor2.x : 800;
58
61
  var pathString = ABCJS.write.sprintf("M %f %f L %f %f",
59
- this.anchor1.x, y1, this.anchor2.x, y2);
62
+ left, y1, right, y2);
60
63
  renderer.printPath({path:pathString, stroke:"#000000", 'class': renderer.addClasses('decoration')});
61
64
  };
@@ -1,5 +1,5 @@
1
1
  // abc_decoration.js: Creates a data structure suitable for printing a line of abc
2
- // Copyright (C) 2010-2015 Gregory Dyke (gregdyke at gmail dot com) & Paul Rosen
2
+ // Copyright (C) 2010-2016 Gregory Dyke (gregdyke at gmail dot com) & Paul Rosen
3
3
  //
4
4
  // This program is free software: you can redistribute it and/or modify
5
5
  // it under the terms of the GNU General Public License as published by
@@ -71,6 +71,7 @@ ABCJS.write.EngraverController = function(paper, params) {
71
71
  if (this.usingSvg && params.add_classes)
72
72
  Raphael._availableAttrs['class'] = "";
73
73
  Raphael._availableAttrs['text-decoration'] = "";
74
+ Raphael._availableAttrs['data-vertical'] = "";
74
75
 
75
76
  //TODO-GD factor out all calls directly made to renderer.paper and fix all the coupling issues below
76
77
  this.renderer=new ABCJS.write.Renderer(paper, params.regression);
@@ -102,7 +103,7 @@ ABCJS.write.EngraverController.prototype.engraveABC = function(abctunes) {
102
103
  this.reset();
103
104
 
104
105
  for (var i = 0; i < abctunes.length; i++) {
105
- this.engraveTune(abctunes[i]);
106
+ this.engraveTune(abctunes[i], i);
106
107
  }
107
108
  if (this.renderer.doRegression)
108
109
  return this.renderer.regressionLines.join("\n");
@@ -121,24 +122,24 @@ ABCJS.write.EngraverController.prototype.adjustNonScaledItems = function (scale)
121
122
  * Run the engraving process on a single tune
122
123
  * @param {ABCJS.Tune} abctune
123
124
  */
124
- ABCJS.write.EngraverController.prototype.engraveTune = function (abctune) {
125
+ ABCJS.write.EngraverController.prototype.engraveTune = function (abctune, tuneNumber) {
125
126
  this.renderer.lineNumber = null;
126
127
  abctune.formatting.tripletfont = {face: "Times", size: 11, weight: "normal", style: "italic", decoration: "none"}; // TODO-PER: This font isn't defined in the standard, so it's hardcoded here for now.
127
128
 
128
129
  this.renderer.abctune = abctune; // TODO-PER: this is just to get the font info.
129
130
  this.renderer.setVerticalSpace(abctune.formatting);
130
131
  this.renderer.measureNumber = null;
131
- var scale = abctune.formatting.scale ? abctune.formatting.scale : this.scale;
132
- if (scale === undefined) scale = abctune.media === 'print' ? 0.75 : 1;
133
132
  this.renderer.setPrintMode(abctune.media === 'print');
133
+ var scale = abctune.formatting.scale ? abctune.formatting.scale : this.scale;
134
+ if (scale === undefined) scale = this.renderer.isPrint ? 0.75 : 1;
134
135
  this.renderer.setPadding(abctune);
135
- this.engraver = new ABCJS.write.AbstractEngraver(abctune.formatting.bagpipes,this.renderer);
136
+ this.engraver = new ABCJS.write.AbstractEngraver(abctune.formatting.bagpipes,this.renderer, tuneNumber);
136
137
  this.engraver.setStemHeight(this.renderer.spacing.stemHeight);
137
138
  this.renderer.engraver = this.engraver; //TODO-PER: do we need this coupling? It's just used for the tempo
138
139
  if (abctune.formatting.staffwidth) {
139
140
  this.width = abctune.formatting.staffwidth * 1.33; // The width is expressed in pt; convert to px.
140
141
  } else {
141
- this.width = abctune.media === 'print' ? this.staffwidthPrint : this.staffwidthScreen;
142
+ this.width = this.renderer.isPrint ? this.staffwidthPrint : this.staffwidthScreen;
142
143
  }
143
144
  this.adjustNonScaledItems(scale);
144
145
 
@@ -198,7 +199,7 @@ ABCJS.write.EngraverController.prototype.engraveTune = function (abctune) {
198
199
  this.engraveStaffLine(abcLine.staffGroup);
199
200
  } else if (abcLine.subtitle && line !== 0) {
200
201
  this.renderer.outputSubtitle(this.width, abcLine.subtitle);
201
- } else if (abcLine.text) {
202
+ } else if (abcLine.text !== undefined) {
202
203
  this.renderer.outputFreeText(abcLine.text);
203
204
  }
204
205
  }
@@ -266,7 +267,7 @@ ABCJS.write.EngraverController.prototype.engraveStaffLine = function (staffGroup
266
267
  * Called by the Abstract Engraving Structure or any other (e.g. midi playback) to say it was selected (notehead clicked on)
267
268
  * @protected
268
269
  */
269
- ABCJS.write.EngraverController.prototype.notifySelect = function (abselem) {
270
+ ABCJS.write.EngraverController.prototype.notifySelect = function (abselem, tuneNumber) {
270
271
  this.clearSelection();
271
272
  if (abselem.highlight) {
272
273
  this.selected = [abselem];
@@ -275,7 +276,7 @@ ABCJS.write.EngraverController.prototype.notifySelect = function (abselem) {
275
276
  var abcelem = abselem.abcelem || {};
276
277
  for (var i=0; i<this.listeners.length;i++) {
277
278
  if (this.listeners[i].highlight)
278
- this.listeners[i].highlight(abcelem);
279
+ this.listeners[i].highlight(abcelem, tuneNumber);
279
280
  }
280
281
  };
281
282
 
@@ -84,7 +84,7 @@ ABCJS.write.Glyphs = function() {
84
84
  'r':{d:[['M',6.33,-9.12],['c',0.27,-0.03,0.93,0.00,1.20,0.06],['c',0.84,0.21,1.23,0.81,1.02,1.53],['c',-0.24,0.75,-0.90,1.17,-1.56,0.96],['c',-0.33,-0.09,-0.51,-0.30,-0.66,-0.75],['c',-0.03,-0.12,-0.09,-0.24,-0.12,-0.30],['c',-0.09,-0.15,-0.30,-0.24,-0.48,-0.24],['c',-0.57,0.00,-1.38,0.54,-1.65,1.08],['c',-0.06,0.15,-0.33,1.17,-0.90,3.27],['c',-0.57,2.31,-0.81,3.12,-0.87,3.21],['c',-0.03,0.06,-0.12,0.15,-0.18,0.21],['l',-0.12,0.06],['l',-0.81,0.03],['c',-0.69,0.00,-0.81,0.00,-0.90,-0.03],['c',-0.09,-0.06,-0.18,-0.21,-0.18,-0.30],['c',0.00,-0.06,0.39,-1.62,0.90,-3.51],['c',0.84,-3.24,0.87,-3.45,0.87,-3.72],['c',0.00,-0.21,0.00,-0.27,-0.03,-0.36],['c',-0.12,-0.15,-0.21,-0.24,-0.42,-0.24],['c',-0.24,0.00,-0.45,0.15,-0.78,0.42],['c',-0.33,0.36,-0.45,0.54,-0.72,1.14],['c',-0.03,0.12,-0.21,0.24,-0.36,0.27],['c',-0.12,0.00,-0.15,0.00,-0.24,-0.06],['c',-0.18,-0.12,-0.18,-0.21,-0.06,-0.54],['c',0.21,-0.57,0.42,-0.93,0.78,-1.32],['c',0.54,-0.51,1.20,-0.81,1.95,-0.87],['c',0.81,-0.03,1.53,0.30,1.92,0.87],['l',0.12,0.18],['l',0.09,-0.09],['c',0.57,-0.45,1.41,-0.84,2.19,-0.96],['z']],w:9.41,h:9.132},
85
85
  '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},
86
86
  '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},
87
- '+':{d:[['M',3.48,-11.19],['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},
87
+ '+':{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},
88
88
  ',':{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
89
  '-':{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},
90
90
  '.':{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},
@@ -102,7 +102,7 @@ ABCJS.write.RelativeElement.prototype.draw = function (renderer, bartop) {
102
102
  case "debug":
103
103
  this.graphelem = renderer.renderText(this.x, renderer.calcY(15), ""+this.c, "debugfont", 'debug-msg', 'start'); break;
104
104
  case "barNumber":
105
- this.graphelem = renderer.renderText(this.x, y, ""+this.c, "measurefont", 'bar-number', "start");
105
+ this.graphelem = renderer.renderText(this.x, y, ""+this.c, "measurefont", 'bar-number', "middle");
106
106
  break;
107
107
  case "lyric":
108
108
  this.graphelem = renderer.renderText(this.x, y, this.c, "vocalfont", 'abc-lyric', "middle");
@@ -130,7 +130,7 @@ ABCJS.write.Renderer.prototype.setPadding = function(abctune) {
130
130
  self.padding[paddingKey] = abctune.formatting[formattingKey];
131
131
  else if (self.paddingOverride[paddingKey] !== undefined)
132
132
  self.padding[paddingKey] = self.paddingOverride[paddingKey];
133
- else if (abctune.media === 'print')
133
+ else if (self.isPrint)
134
134
  self.padding[paddingKey] = printDefault;
135
135
  else
136
136
  self.padding[paddingKey] = screenDefault;
@@ -138,7 +138,7 @@ ABCJS.write.Renderer.prototype.setPadding = function(abctune) {
138
138
  // 1cm x 0.393701in/cm x 72pt/in x 1.33px/pt = 38px
139
139
  // 1.8cm x 0.393701in/cm x 72pt/in x 1.33px/pt = 68px
140
140
  setPaddingVariable(this, 'top', 'topmargin', 38, 15);
141
- setPaddingVariable(this, 'bottom', 'bottommargin', 38, 15);
141
+ setPaddingVariable(this, 'bottom', 'botmargin', 38, 15);
142
142
  setPaddingVariable(this, 'left', 'leftmargin', 68, 15);
143
143
  setPaddingVariable(this, 'right', 'rightmargin', 68, 15);
144
144
  };
@@ -367,14 +367,24 @@ ABCJS.write.Renderer.prototype.engraveExtraText = function(width, abctune) {
367
367
  * @param {array or string} text
368
368
  */
369
369
  ABCJS.write.Renderer.prototype.outputFreeText = function (text) {
370
- if (typeof text === 'string')
370
+ if (text === "") { // we do want to print out blank lines if they have been specified.
371
+ var hash = this.getFontAndAttr('textfont', 'defined-text');
372
+ this.moveY(hash.attr['font-size'] * 2); // move the distance of the line, plus the distance of the margin, which is also one line.
373
+ } else if (typeof text === 'string')
371
374
  this.outputTextIf(this.padding.left, text, 'textfont', 'defined-text', 0, 1, "start");
372
375
  else {
373
376
  var str = "";
377
+ var isCentered = false; // The structure is wrong here: it requires an array to do centering, but it shouldn't have.
374
378
  for (var i = 0; i < text.length; i++) {
375
- str += " FONT " + text[i].text;
379
+ if (text[i].font)
380
+ str += "FONT(" + text[i].font + ")";
381
+ str += text[i].text;
382
+ if (text[i].center)
383
+ isCentered = true;
376
384
  }
377
- this.outputTextIf(this.padding.left, str, 'textfont', 'defined-text', 0, 1, "start");
385
+ var alignment = isCentered ? 'middle' : 'start';
386
+ var x = isCentered ? this.controller.width / 2 : this.padding.left;
387
+ this.outputTextIf(x, str, 'textfont', 'defined-text', 0, 1, alignment);
378
388
  }
379
389
  };
380
390
 
@@ -548,7 +558,43 @@ ABCJS.write.Renderer.prototype.printPath = function (attrs) {
548
558
  return ret;
549
559
  };
550
560
 
551
- ABCJS.write.Renderer.prototype.drawArc = function(x1, x2, pitch1, pitch2, above) {
561
+ ABCJS.write.Renderer.prototype.drawBrace = function(xLeft, yTop, yBottom) {//Tony
562
+ var yHeight = yBottom - yTop;
563
+
564
+ var xCurve = [7.5, -8, 21, 0, 18.5, -10.5, 7.5];
565
+ var yCurve = [0, yHeight/5.5, yHeight/3.14, yHeight/2, yHeight/2.93, yHeight/4.88, 0];
566
+
567
+ var pathString = ABCJS.write.sprintf("M %f %f C %f %f %f %f %f %f C %f %f %f %f %f %f z",
568
+ xLeft+xCurve[0], yTop+yCurve[0],
569
+ xLeft+xCurve[1], yTop+yCurve[1],
570
+ xLeft+xCurve[2], yTop+yCurve[2],
571
+ xLeft+xCurve[3], yTop+yCurve[3],
572
+ xLeft+xCurve[4], yTop+yCurve[4],
573
+ xLeft+xCurve[5], yTop+yCurve[5],
574
+ xLeft+xCurve[6], yTop+yCurve[6]);
575
+ var ret1 = this.paper.path().attr({path:pathString, stroke:"#000000", fill:"#000000", 'class': this.addClasses('brace')});
576
+
577
+ xCurve = [0, 17.5, -7.5, 6.6, -5, 20, 0];
578
+ yCurve = [yHeight/2, yHeight/1.46, yHeight/1.22, yHeight, yHeight/1.19, yHeight/1.42, yHeight/2];
579
+
580
+ pathString = ABCJS.write.sprintf("M %f %f C %f %f %f %f %f %f C %f %f %f %f %f %f z",
581
+ xLeft+xCurve[ 0], yTop+yCurve[0],
582
+ xLeft+xCurve[1], yTop+yCurve[1],
583
+ xLeft+xCurve[2], yTop+yCurve[2],
584
+ xLeft+xCurve[3], yTop+yCurve[3],
585
+ xLeft+xCurve[4], yTop+yCurve[4],
586
+ xLeft+xCurve[5], yTop+yCurve[5],
587
+ xLeft+xCurve[6], yTop+yCurve[6]);
588
+ var ret2 = this.paper.path().attr({path:pathString, stroke:"#000000", fill:"#000000", 'class': this.addClasses('brace')});
589
+
590
+ if (this.doRegression){
591
+ this.addToRegression(ret1);
592
+ this.addToRegression(ret2);
593
+ }
594
+ return ret1 + ret2;
595
+ };
596
+
597
+ ABCJS.write.Renderer.prototype.drawArc = function(x1, x2, pitch1, pitch2, above, klass) {
552
598
 
553
599
 
554
600
  x1 = x1 + 6;
@@ -576,7 +622,11 @@ ABCJS.write.Renderer.prototype.drawArc = function(x1, x2, pitch1, pitch2, above)
576
622
  var pathString = ABCJS.write.sprintf("M %f %f C %f %f %f %f %f %f C %f %f %f %f %f %f z", x1, y1,
577
623
  controlx1, controly1, controlx2, controly2, x2, y2,
578
624
  controlx2-thickness*uy, controly2+thickness*ux, controlx1-thickness*uy, controly1+thickness*ux, x1, y1);
579
- var ret = this.paper.path().attr({path:pathString, stroke:"none", fill:"#000000", 'class': this.addClasses('slur')});
625
+ if (klass)
626
+ klass += ' slur';
627
+ else
628
+ klass = 'slur';
629
+ var ret = this.paper.path().attr({path:pathString, stroke:"none", fill:"#000000", 'class': this.addClasses(klass)});
580
630
  if (this.doRegression) this.addToRegression(ret);
581
631
 
582
632
  return ret;
@@ -622,7 +672,7 @@ ABCJS.write.Renderer.prototype.getFontAndAttr = function(type, klass) {
622
672
  var font = this.abctune.formatting[type];
623
673
  // Raphael deliberately changes the font units to pixels for some reason, so we need to change points to pixels here.
624
674
  if (font)
625
- font = { face: font.face, size: font.size*4/3, decoration: font.decoration, style: font.style, weight: font.weight };
675
+ font = { face: font.face, size: font.size*4/3, decoration: font.decoration, style: font.style, weight: font.weight, box: font.box };
626
676
  else
627
677
  font = { face: "Arial", size: 12*4/3, decoration: "underline", style: "normal", weight: "normal" };
628
678
 
@@ -637,6 +687,8 @@ ABCJS.write.Renderer.prototype.getTextSize = function(text, type, klass) {
637
687
  var hash = this.getFontAndAttr(type, klass);
638
688
  var el = this.paper.text(0,0, text).attr(hash.attr);
639
689
  var size = el.getBBox();
690
+ if (isNaN(size.height)) // This can happen if the element isn't visible.
691
+ size = { width: 0, height: 0};
640
692
  el.remove();
641
693
  return size;
642
694
  };
@@ -651,9 +703,13 @@ ABCJS.write.Renderer.prototype.renderText = function(x, y, text, type, klass, an
651
703
  // The text will be placed centered in vertical alignment, so we need to move the box down so that
652
704
  // the top of the text is where we've requested.
653
705
  var size = el.getBBox();
654
- el.attr({ "y": y + size.height / 2 });
655
- if (hash.font.box) {
656
- this.paper.rect(size.x - 1, size.y - 1, size.width + 2, size.height + 2).attr({"stroke": "#cccccc"});
706
+ if (isNaN(size.height)) // This can happen if the element is hidden.
707
+ el.attr({ "y": y });
708
+ else {
709
+ el.attr({"y": y + size.height / 2});
710
+ if (hash.font.box) {
711
+ this.paper.rect(size.x - 1, size.y + size.height / 2 - 1, size.width + 2, size.height + 2).attr({"stroke": "#888888"});
712
+ }
657
713
  }
658
714
  }
659
715
  if (type === 'debugfont') {
@@ -681,15 +737,31 @@ ABCJS.write.Renderer.prototype.outputTextIf = function(x, str, kind, klass, marg
681
737
  if (marginTop)
682
738
  this.moveY(marginTop);
683
739
  var el = this.renderText(x, this.y, str, kind, klass, alignment);
740
+ var bb = el.getBBox(); // This can return NaN if the element isn't visible.
741
+ var width = isNaN(bb.width) ? 0 : bb.width;
742
+ var height = isNaN(bb.height) ? 0 : bb.height;
684
743
  if (marginBottom !== null) {
685
744
  var numLines = str.split("\n").length;
686
- this.moveY(el.getBBox().height/numLines, (numLines + marginBottom));
745
+ if (!isNaN(bb.height))
746
+ this.moveY(height/numLines, (numLines + marginBottom));
687
747
  }
688
- return [el.getBBox().width, el.getBBox().height];
748
+ return [width, height];
689
749
  }
690
750
  return [0,0];
691
751
  };
692
752
 
753
+ ABCJS.write.Renderer.prototype.addInvisibleMarker = function (className) {
754
+ var dy = 0.35;
755
+ var fill = "rgba(0,0,0,0)";
756
+ var y = this.y;
757
+ y = Math.round(y);
758
+ var x1 = 0;
759
+ var x2 = 100;
760
+ var pathString = ABCJS.write.sprintf("M %f %f L %f %f L %f %f L %f %f z", x1, y-dy, x1+x2, y-dy,
761
+ x2, y+dy, x1, y+dy);
762
+ this.paper.path().attr({path:pathString, stroke:"none", fill:fill, 'class': this.addClasses(className), 'data-vertical': y }).toBack();
763
+ };
764
+
693
765
  // For debugging, it is sometimes useful to know where you are vertically.
694
766
  ABCJS.write.Renderer.prototype.printHorizontalLine = function (width, vertical, comment) {
695
767
  var dy = 0.35;
@@ -52,6 +52,7 @@ if (!window.ABCJS.write)
52
52
  ABCJS.write.StaffGroupElement = function() {
53
53
  this.voices = [];
54
54
  this.staffs = [];
55
+ this.brace = undefined; //tony
55
56
  };
56
57
 
57
58
  ABCJS.write.StaffGroupElement.prototype.setLimit = function(member, voice) {
@@ -217,6 +218,11 @@ ABCJS.write.StaffGroupElement.prototype.layout = function(spacing, renderer, deb
217
218
  }
218
219
  x=x+voiceheaderw*1.1; // When there is no voice header, 110% of 0 is 0
219
220
  this.startx=x;
221
+ if (this.brace) {
222
+ this.brace.setLocation(this.startx);
223
+ x += this.brace.getWidth();
224
+ this.startx = x;
225
+ }
220
226
 
221
227
  var currentduration = 0;
222
228
  if (debug) console.log("init layout");
@@ -342,6 +348,9 @@ ABCJS.write.StaffGroupElement.prototype.draw = function (renderer) {
342
348
  };
343
349
  }
344
350
 
351
+ // An invisible marker is useful to be able to find where each system starts.
352
+ renderer.addInvisibleMarker("abcjs-top-of-system");
353
+
345
354
  var startY = renderer.y; // So that it can be restored after we're done.
346
355
  // Set the absolute Y position for each staff here, so the voice drawing below can just use if.
347
356
  for (var j = 0; j < this.staffs.length; j++) {
@@ -391,6 +400,13 @@ ABCJS.write.StaffGroupElement.prototype.draw = function (renderer) {
391
400
  // if (staff.bottom < 0)
392
401
  // renderer.moveY(ABCJS.write.spacing.STEP, -staff.bottom);
393
402
  }
403
+ if(this.brace) {//Tony
404
+ if (i === this.brace.length - 1) {
405
+ if (this.brace) {
406
+ this.brace.draw(renderer, topLine, bottomLine); //tony
407
+ }
408
+ }
409
+ }
394
410
  }
395
411
  renderer.measureNumber = null;
396
412