abcjs-rails 1.11 → 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 (31) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/javascripts/abcjs/api/abc_animation.js +41 -1
  3. data/app/assets/javascripts/abcjs/api/abc_tunebook.js +5 -0
  4. data/app/assets/javascripts/abcjs/data/abc_tune.js +4 -3
  5. data/app/assets/javascripts/abcjs/edit/abc_editor.js +10 -0
  6. data/app/assets/javascripts/abcjs/parse/abc_parse.js +120 -19
  7. data/app/assets/javascripts/abcjs/parse/abc_parse_directive.js +456 -115
  8. data/app/assets/javascripts/abcjs/raphael.js +2 -2
  9. data/app/assets/javascripts/abcjs/write/abc_absolute_element.js +111 -4
  10. data/app/assets/javascripts/abcjs/write/abc_abstract_engraver.js +899 -0
  11. data/app/assets/javascripts/abcjs/write/abc_beam_element.js +263 -37
  12. data/app/assets/javascripts/abcjs/write/abc_create_clef.js +76 -0
  13. data/app/assets/javascripts/abcjs/write/abc_create_key_signature.js +41 -0
  14. data/app/assets/javascripts/abcjs/write/abc_create_time_signature.js +51 -0
  15. data/app/assets/javascripts/abcjs/write/{abc_cresendo_element.js → abc_crescendo_element.js} +32 -1
  16. data/app/assets/javascripts/abcjs/write/abc_decoration.js +321 -0
  17. data/app/assets/javascripts/abcjs/write/abc_dynamic_decoration.js +22 -1
  18. data/app/assets/javascripts/abcjs/write/abc_ending_element.js +31 -1
  19. data/app/assets/javascripts/abcjs/write/abc_engraver_controller.js +359 -0
  20. data/app/assets/javascripts/abcjs/write/abc_glyphs.js +119 -9
  21. data/app/assets/javascripts/abcjs/write/abc_layout.js +2 -2
  22. data/app/assets/javascripts/abcjs/write/abc_relative_element.js +106 -8
  23. data/app/assets/javascripts/abcjs/write/abc_renderer.js +754 -0
  24. data/app/assets/javascripts/abcjs/write/abc_staff_group_element.js +249 -9
  25. data/app/assets/javascripts/abcjs/write/abc_tempo_element.js +104 -0
  26. data/app/assets/javascripts/abcjs/write/abc_tie_element.js +69 -22
  27. data/app/assets/javascripts/abcjs/write/abc_triplet_element.js +77 -10
  28. data/app/assets/javascripts/abcjs/write/abc_voice_element.js +100 -8
  29. data/app/assets/javascripts/abcjs/write/abc_write.js +64 -68
  30. data/lib/abcjs-rails/version.rb +1 -1
  31. metadata +12 -4
@@ -22,40 +22,192 @@ if (!window.ABCJS)
22
22
  if (!window.ABCJS.write)
23
23
  window.ABCJS.write = {};
24
24
 
25
- ABCJS.write.BeamElem = function(type, flat) {
26
- this.isflat = (flat);
27
- this.isgrace = (type && type==="grace");
28
- this.forceup = (type && type==="up");
29
- this.forcedown = (type && type==="down");
30
- this.elems = []; // all the ABCJS.write.AbsoluteElements
31
- this.total = 0;
32
- this.dy = (this.asc)?ABCJS.write.spacing.STEP*1.2:-ABCJS.write.spacing.STEP*1.2;
33
- if (this.isgrace) this.dy = this.dy*0.4;
34
- this.allrests = true;
35
- };
25
+ // Most elements on the page are related to a particular absolute element -- notes, rests, bars, etc. Beams, however, span multiple elements.
26
+ // This means that beams can't be laid out until the absolute elements are placed. There is the further complication that the stems for beamed
27
+ // notes can't be laid out until the beams are because we don't know how long they will be until we know the slope of the beam and the horizontal
28
+ // spacing of the absolute elements.
29
+ //
30
+ // So, when a beam is detected, a BeamElem is created, then all notes belonging to that beam are added to it. These notes are not given stems at that time.
31
+ // Then, after the horizontal layout is complete, all of the BeamElem are iterated to set the beam position, then all of the notes that are beamed are given
32
+ // stems. After that, we are ready for the drawing step.
33
+
34
+ // There are three phases: the setup phase, when new elements are being discovered, the layout phase, when everything is calculated, and the drawing phase,
35
+ // when the object is not changed, but is used to put the elements on the page.
36
+
37
+ (function() {
38
+ "use strict";
39
+
40
+ //
41
+ // Setup phase
42
+ //
43
+ ABCJS.write.BeamElem = function(stemHeight, type, flat) {
44
+ // type is "grace", "up", "down", or undefined. flat is used to force flat beams, as it commonly found in the grace notes of bagpipe music.
45
+ this.isflat = flat;
46
+ this.isgrace = (type && type === "grace");
47
+ this.forceup = this.isgrace || (type && type === "up");
48
+ this.forcedown = (type && type === "down");
49
+ this.elems = []; // all the ABCJS.write.AbsoluteElements that this beam touches. It may include embedded rests.
50
+ this.total = 0;
51
+ this.allrests = true;
52
+ this.stemHeight = stemHeight;
53
+ this.beams = []; // During the layout phase, this will become a list of the beams that need to be drawn.
54
+ };
55
+
56
+ ABCJS.write.BeamElem.prototype.add = function(abselem) {
57
+ var pitch = abselem.abcelem.averagepitch;
58
+ if (pitch === undefined) return; // don't include elements like spacers in beams
59
+ this.allrests = this.allrests && abselem.abcelem.rest;
60
+ abselem.beam = this;
61
+ this.elems.push(abselem);
62
+ //var pitch = abselem.abcelem.averagepitch;
63
+ this.total += pitch; // TODO CHORD (get pitches from abselem.heads)
64
+ if (!this.min || abselem.abcelem.minpitch < this.min) {
65
+ this.min = abselem.abcelem.minpitch;
66
+ }
67
+ if (!this.max || abselem.abcelem.maxpitch > this.max) {
68
+ this.max = abselem.abcelem.maxpitch;
69
+ }
70
+ };
71
+
72
+ var middleLine = 6; // hardcoded 6 is B
73
+
74
+ ABCJS.write.BeamElem.prototype.calcDir = function() {
75
+ if (this.forceup) return true;
76
+ if (this.forcedown) return false;
77
+ var average = calcAverage(this.total, this.elems.length);
78
+ return average < middleLine;
79
+ };
80
+
81
+ //
82
+ // layout phase
83
+ //
84
+ ABCJS.write.BeamElem.prototype.layout = function() {
85
+ if (this.elems.length === 0 || this.allrests) return;
86
+
87
+ this.stemsUp = this.calcDir(); // True means the stems are facing up.
88
+ var dy = calcDy(this.stemsUp, this.isgrace); // This is the width of the beam line.
89
+
90
+ // create the main beam
91
+ var firstElement = this.elems[0];
92
+ var lastElement = this.elems[this.elems.length - 1];
93
+ var yPos = calcYPos(this.total, this.elems.length, this.stemHeight, this.stemsUp, firstElement.abcelem.averagepitch, lastElement.abcelem.averagepitch, this.isflat, this.min, this.max, this.isgrace);
94
+ var xPos = calcXPos(this.stemsUp, firstElement, lastElement);
95
+ this.beams.push({ startX: xPos[0], endX: xPos[1], startY: yPos[0], endY: yPos[1], dy: dy });
96
+
97
+ // create the rest of the beams (in the case of 1/16th notes, etc.
98
+ var beams = createAdditionalBeams(this.elems, this.stemsUp, this.beams[0], this.isgrace, dy);
99
+ for (var i = 0; i < beams.length; i++)
100
+ this.beams.push(beams[i]);
101
+
102
+ // Now that the main beam is defined, we know how tall the stems should be, so create them and attach them to the original notes.
103
+ createStems(this.elems, this.stemsUp, this.beams[0], dy, this.mainNote);
104
+ };
105
+
106
+ ABCJS.write.BeamElem.prototype.isAbove = function() {
107
+ return this.stemsUp;
108
+ };
109
+
110
+ // We can't just use the entire beam for the calculation. The range has to be passed in, because the beam might extend into some unrelated notes. for instance, (3_a'f'e'f'2 when L:16
111
+ ABCJS.write.BeamElem.prototype.heightAtMidpoint = function(startX, endX) {
112
+ if (this.beams.length === 0)
113
+ return 0;
114
+ var beam = this.beams[0];
115
+ var midPoint = startX + (endX - startX) / 2;
116
+ return getBarYAt(beam.startX, beam.startY, beam.endX, beam.endY, midPoint);
117
+ };
118
+
119
+ ABCJS.write.BeamElem.prototype.xAtMidpoint = function(startX, endX) {
120
+ return startX + (endX - startX)/2;
121
+ };
122
+
123
+ //
124
+ // Drawing phase
125
+ //
126
+ ABCJS.write.BeamElem.prototype.draw = function(renderer) {
127
+ if (this.beams.length === 0) return;
128
+
129
+ renderer.beginGroup();
130
+ for (var i = 0; i < this.beams.length; i++) {
131
+ var beam = this.beams[i];
132
+ drawBeam(renderer, beam.startX, beam.startY, beam.endX, beam.endY, beam.dy);
133
+ }
134
+ renderer.endGroup('beam-elem');
135
+ };
136
+
137
+ //
138
+ // private functions
139
+ //
140
+ function calcSlant(leftAveragePitch, rightAveragePitch, numStems, isFlat) {
141
+ if (isFlat)
142
+ return 0;
143
+ var slant = leftAveragePitch - rightAveragePitch;
144
+ var maxSlant = numStems / 2;
36
145
 
37
- ABCJS.write.BeamElem.prototype.add = function(abselem) {
38
- var pitch = abselem.abcelem.averagepitch;
39
- if (pitch===undefined) return; // don't include elements like spacers in beams
40
- this.allrests = this.allrests && abselem.abcelem.rest;
41
- abselem.beam = this;
42
- this.elems.push(abselem);
43
- //var pitch = abselem.abcelem.averagepitch;
44
- this.total += pitch; // TODO CHORD (get pitches from abselem.heads)
45
- if (!this.min || abselem.abcelem.minpitch<this.min) {
46
- this.min = abselem.abcelem.minpitch;
146
+ if (slant > maxSlant) slant = maxSlant;
147
+ if (slant < -maxSlant) slant = -maxSlant;
148
+ return slant;
47
149
  }
48
- if (!this.max || abselem.abcelem.maxpitch>this.max) {
49
- this.max = abselem.abcelem.maxpitch;
150
+
151
+ function calcAverage(total, numElements) {
152
+ if (!numElements)
153
+ return 0;
154
+ return total / numElements;
155
+ }
156
+
157
+ function getBarYAt(startx, starty, endx, endy, x) {
158
+ return starty + (endy - starty) / (endx - startx) * (x - startx);
159
+ }
160
+
161
+ function calcDy(asc, isGrace) {
162
+ var dy = (asc) ? ABCJS.write.spacing.STEP : -ABCJS.write.spacing.STEP;
163
+ if (isGrace) dy = dy * 0.4;
164
+ return dy;
50
165
  }
51
- };
52
166
 
53
- ABCJS.write.BeamElem.prototype.average = function() {
54
- try {
55
- return this.total/this.elems.length;
56
- } catch (e) {
57
- return 0;
167
+ function drawBeam(renderer, startX, startY, endX, endY, dy) {
168
+ // the X coordinates are actual coordinates, but the Y coordinates are in pitches.
169
+ startY = renderer.calcY(startY);
170
+ endY = renderer.calcY(endY);
171
+ var pathString = "M" + startX + " " + startY + " L" + endX + " " + endY +
172
+ "L" + endX + " " + (endY + dy) + " L" + startX + " " + (startY + dy) + "z";
173
+ renderer.printPath({
174
+ path: pathString,
175
+ stroke: "none",
176
+ fill: "#000000",
177
+ 'class': renderer.addClasses('beam-elem')
178
+ });
58
179
  }
180
+ <<<<<<< HEAD
181
+
182
+ function calcXPos(asc, firstElement, lastElement) {
183
+ var starthead = firstElement.heads[asc ? 0 : firstElement.heads.length - 1];
184
+ var endhead = lastElement.heads[asc ? 0 : lastElement.heads.length - 1];
185
+ var startX = starthead.x;
186
+ if (asc) startX += starthead.w - 0.6;
187
+ var endX = endhead.x;
188
+ if (asc) endX += endhead.w;
189
+ return [ startX, endX ];
190
+ }
191
+
192
+ function calcYPos(total, numElements, stemHeight, asc, firstAveragePitch, lastAveragePitch, isFlat, minPitch, maxPitch, isGrace) {
193
+ var average = calcAverage(total, numElements); // This is the average pitch for the all the notes that will be beamed.
194
+ var barpos = stemHeight - 2; // (isGrace)? 5:7;
195
+ var barminpos = stemHeight - 2;
196
+ var pos = Math.round(asc ? Math.max(average + barpos, maxPitch + barminpos) : Math.min(average - barpos, minPitch - barminpos));
197
+
198
+ var slant = calcSlant(firstAveragePitch, lastAveragePitch, numElements, isFlat);
199
+ var startY = pos + Math.floor(slant / 2);
200
+ var endY = pos + Math.floor(-slant / 2);
201
+
202
+ // If the notes are too high or too low, make the beam go down to the middle
203
+ if (!isGrace) {
204
+ if (asc && pos < 6) {
205
+ startY = 6;
206
+ endY = 6;
207
+ } else if (!asc && pos > 6) {
208
+ startY = 6;
209
+ endY = 6;
210
+ =======
59
211
  };
60
212
 
61
213
  ABCJS.write.BeamElem.prototype.draw = function(renderer) {
@@ -131,32 +283,106 @@ ABCJS.write.BeamElem.prototype.drawStems = function(renderer) {
131
283
  } else {
132
284
  auxbeams[-4-durlog] = {x:x+((this.asc)?-0.6:0), y:bary+sy*(-4-durlog+1),
133
285
  durlog:durlog, single:true};
286
+ >>>>>>> origin/master
134
287
  }
135
288
  }
136
289
 
137
- for (var j=auxbeams.length-1;j>=0;j--) {
138
- if (i===ii-1 || ABCJS.write.getDurlog(this.elems[i+1].abcelem.duration)>(-j-4)) {
290
+ return [ startY, endY];
291
+ }
139
292
 
140
- var auxbeamendx = x;
141
- var auxbeamendy = bary + sy*(j+1);
293
+ function createStems(elems, asc, beam, dy, mainNote) {
294
+ for (var i = 0; i < elems.length; i++) {
295
+ var elem = elems[i];
296
+ if (elem.abcelem.rest)
297
+ continue;
298
+ // TODO-PER: This is odd. If it is a regular beam then elems is an array of AbsoluteElements, if it is a grace beam then it is an array of objects , so we directly attach the element to the parent. We tell it if is a grace note because they are passed in as a generic object instead of an AbsoluteElement.
299
+ var isGrace = elem.addExtra ? false : true;
300
+ var parent = isGrace ? mainNote : elem;
301
+ var furthestHead = elem.heads[(asc) ? 0 : elem.heads.length - 1];
302
+ var ovalDelta = 1 / 5;//(isGrace)?1/3:1/5;
303
+ var pitch = furthestHead.pitch + ((asc) ? ovalDelta : -ovalDelta);
304
+ var dx = asc ? furthestHead.w : 0; // down-pointing stems start on the left side of the note, up-pointing stems start on the right side, so we offset by the note width.
305
+ var x = furthestHead.x + dx; // this is now the actual x location in pixels.
306
+ var bary = getBarYAt(beam.startX, beam.startY, beam.endX, beam.endY, x);
307
+ var lineWidth = (asc) ? -0.6 : 0.6;
308
+ if (!asc)
309
+ bary -= (dy / 2) / ABCJS.write.spacing.STEP; // TODO-PER: This is just a fudge factor so the down-pointing stems don't overlap.
310
+ if (isGrace)
311
+ dx += elem.heads[0].dx;
312
+ // TODO-PER-HACK: One type of note head has a different placement of the stem. This should be more generically calculated:
313
+ if (furthestHead.c === 'noteheads.slash.quarter') {
314
+ if (asc)
315
+ pitch += 1;
316
+ else
317
+ pitch -= 1;
318
+ }
319
+ var stem = new ABCJS.write.RelativeElement(null, dx, 0, pitch, {
320
+ "type": "stem",
321
+ "pitch2": bary,
322
+ linewidth: lineWidth
323
+ });
324
+ stem.setX(parent.x); // This is after the x coordinates were set, so we have to set it directly.
325
+ parent.addExtra(stem);
326
+ }
327
+
328
+ }
142
329
 
330
+ function createAdditionalBeams(elems, asc, beam, isGrace, dy) {
331
+ var beams = [];
332
+ var auxBeams = []; // auxbeam will be {x, y, durlog, single} auxbeam[0] should match with durlog=-4 (16th) (j=-4-durlog)
333
+ for (var i = 0; i < elems.length; i++) {
334
+ var elem = elems[i];
335
+ if (elem.abcelem.rest)
336
+ continue;
337
+ var furthestHead = elem.heads[(asc) ? 0 : elem.heads.length - 1];
338
+ var x = furthestHead.x + ((asc) ? furthestHead.w : 0);
339
+ var bary = getBarYAt(beam.startX, beam.startY, beam.endX, beam.endY, x);
143
340
 
144
- if (auxbeams[j].single) {
145
- auxbeamendx = (i===0) ? x+5 : x-5;
146
- auxbeamendy = this.getBarYAt(auxbeamendx) + sy*(j+1);
341
+ var sy = (asc) ? -1.5 : 1.5;
342
+ if (isGrace) sy = sy * 2 / 3; // This makes the second beam on grace notes closer to the first one.
343
+ for (var durlog = ABCJS.write.getDurlog(elem.abcelem.duration); durlog < -3; durlog++) { // get the duration via abcelem because of triplets
344
+ if (auxBeams[-4 - durlog]) {
345
+ auxBeams[-4 - durlog].single = false;
346
+ } else {
347
+ auxBeams[-4 - durlog] = {
348
+ x: x + ((asc) ? -0.6 : 0), y: bary + sy * (-4 - durlog + 1),
349
+ durlog: durlog, single: true
350
+ };
147
351
  }
148
- // TODO I think they are drawn from front to back, hence the small x difference with the main beam
352
+ }
353
+
354
+ <<<<<<< HEAD
355
+ for (var j = auxBeams.length - 1; j >= 0; j--) {
356
+ if (i === elems.length - 1 || ABCJS.write.getDurlog(elems[i + 1].abcelem.duration) > (-j - 4)) {
357
+
358
+ var auxBeamEndX = x;
359
+ var auxBeamEndY = bary + sy * (j + 1);
149
360
 
361
+
362
+ if (auxBeams[j].single) {
363
+ auxBeamEndX = (i === 0) ? x + 5 : x - 5;
364
+ auxBeamEndY = getBarYAt(beam.startX, beam.startY, beam.endX, beam.endY, auxBeamEndX) + sy * (j + 1);
365
+ }
366
+ beams.push({ startX: auxBeams[j].x, endX: auxBeamEndX, startY: auxBeams[j].y, endY: auxBeamEndY, dy: dy });
367
+ auxBeams = auxBeams.slice(0, j);
368
+ }
369
+ =======
150
370
  var pathString ="M"+auxbeams[j].x+" "+auxbeams[j].y+" L"+auxbeamendx+" "+auxbeamendy+
151
371
  "L"+auxbeamendx+" "+(auxbeamendy+this.dy) +" L"+auxbeams[j].x+" "+(auxbeams[j].y+this.dy)+"z";
152
372
  renderer.printPath({path:pathString, stroke:"none", fill:"#000000", 'class': renderer.addClasses('beam-elem')});
153
373
  auxbeams = auxbeams.slice(0,j);
374
+ >>>>>>> origin/master
154
375
  }
155
376
  }
377
+ return beams;
156
378
  }
379
+ <<<<<<< HEAD
380
+ })();
381
+ =======
157
382
  renderer.endGroup('beam-elem');
158
383
  };
159
384
 
160
385
  ABCJS.write.BeamElem.prototype.getBarYAt = function(x) {
161
386
  return this.starty + (this.endy-this.starty)/(this.endx-this.startx)*(x-this.startx);
162
387
  };
388
+ >>>>>>> origin/master
@@ -0,0 +1,76 @@
1
+ // abc_create_clef.js
2
+ // Copyright (C) 2010,2015 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
+ if (!window.ABCJS.write)
23
+ window.ABCJS.write = {};
24
+
25
+ (function() {
26
+ "use strict";
27
+
28
+ ABCJS.write.createClef = function(elem) {
29
+ var clef;
30
+ var octave = 0;
31
+ var abselem = new ABCJS.write.AbsoluteElement(elem,0,10, 'staff-extra');
32
+ switch (elem.type) {
33
+ case "treble": clef = "clefs.G"; break;
34
+ case "tenor": clef="clefs.C"; break;
35
+ case "alto": clef="clefs.C"; break;
36
+ case "bass": clef="clefs.F"; break;
37
+ case 'treble+8': clef = "clefs.G"; octave = 1; break;
38
+ case 'tenor+8':clef="clefs.C"; octave = 1; break;
39
+ case 'bass+8': clef="clefs.F"; octave = 1; break;
40
+ case 'alto+8': clef="clefs.C"; octave = 1; break;
41
+ case 'treble-8': clef = "clefs.G"; octave = -1; break;
42
+ case 'tenor-8':clef="clefs.C"; octave = -1; break;
43
+ case 'bass-8': clef="clefs.F"; octave = -1; break;
44
+ case 'alto-8': clef="clefs.C"; octave = -1; break;
45
+ case 'none': return null;
46
+ case 'perc': clef="clefs.perc"; break;
47
+ default: abselem.addChild(new ABCJS.write.RelativeElement("clef="+elem.type, 0, 0, undefined, {type:"debug"}));
48
+ }
49
+ // if (elem.verticalPos) {
50
+ // pitch = elem.verticalPos;
51
+ // }
52
+ var dx =5;
53
+ if (clef) {
54
+ abselem.addRight(new ABCJS.write.RelativeElement(clef, dx, ABCJS.write.glyphs.getSymbolWidth(clef), elem.clefPos));
55
+
56
+ if (clef === 'clefs.G') {
57
+ abselem.top = 13;
58
+ abselem.bottom = -1;
59
+ } else {
60
+ abselem.top = 10;
61
+ abselem.bottom = 2;
62
+ }
63
+ if (octave !== 0) {
64
+ var scale = 2 / 3;
65
+ var adjustspacing = (ABCJS.write.glyphs.getSymbolWidth(clef) - ABCJS.write.glyphs.getSymbolWidth("8") * scale) / 2;
66
+ abselem.addRight(new ABCJS.write.RelativeElement("8", dx + adjustspacing, ABCJS.write.glyphs.getSymbolWidth("8") * scale, (octave > 0) ? abselem.top + 3 : abselem.bottom - 1, {
67
+ scalex: scale,
68
+ scaley: scale
69
+ }));
70
+ abselem.top += 2;
71
+ }
72
+ }
73
+ return abselem;
74
+ };
75
+
76
+ })();
@@ -0,0 +1,41 @@
1
+ // abc_create_key_signature.js
2
+ // Copyright (C) 2010,2015 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
+ if (!window.ABCJS.write)
23
+ window.ABCJS.write = {};
24
+
25
+ (function() {
26
+ "use strict";
27
+
28
+ ABCJS.write.createKeySignature = function(elem) {
29
+ if (!elem.accidentals || elem.accidentals.length === 0)
30
+ return null;
31
+ var abselem = new ABCJS.write.AbsoluteElement(elem, 0, 10, 'staff-extra');
32
+ var dx = 0;
33
+ window.ABCJS.parse.each(elem.accidentals, function(acc) {
34
+ var symbol = (acc.acc === "sharp") ? "accidentals.sharp" : (acc.acc === "natural") ? "accidentals.nat" : "accidentals.flat";
35
+ //var notes = { '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 };
36
+ abselem.addRight(new ABCJS.write.RelativeElement(symbol, dx, ABCJS.write.glyphs.getSymbolWidth(symbol), acc.verticalPos, {thickness: ABCJS.write.glyphs.symbolHeightInPitches(symbol)}));
37
+ dx += ABCJS.write.glyphs.getSymbolWidth(symbol) + 2;
38
+ }, this);
39
+ return abselem;
40
+ };
41
+ })();