abcjs-rails 1.11 → 2.0

Sign up to get free protection for your applications and to get access to all the features.
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
+ })();