abcjs-rails 1.11 → 2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/assets/javascripts/abcjs/api/abc_animation.js +41 -1
- data/app/assets/javascripts/abcjs/api/abc_tunebook.js +5 -0
- data/app/assets/javascripts/abcjs/data/abc_tune.js +4 -3
- data/app/assets/javascripts/abcjs/edit/abc_editor.js +10 -0
- data/app/assets/javascripts/abcjs/parse/abc_parse.js +120 -19
- data/app/assets/javascripts/abcjs/parse/abc_parse_directive.js +456 -115
- data/app/assets/javascripts/abcjs/raphael.js +2 -2
- data/app/assets/javascripts/abcjs/write/abc_absolute_element.js +111 -4
- data/app/assets/javascripts/abcjs/write/abc_abstract_engraver.js +899 -0
- data/app/assets/javascripts/abcjs/write/abc_beam_element.js +263 -37
- data/app/assets/javascripts/abcjs/write/abc_create_clef.js +76 -0
- data/app/assets/javascripts/abcjs/write/abc_create_key_signature.js +41 -0
- data/app/assets/javascripts/abcjs/write/abc_create_time_signature.js +51 -0
- data/app/assets/javascripts/abcjs/write/{abc_cresendo_element.js → abc_crescendo_element.js} +32 -1
- data/app/assets/javascripts/abcjs/write/abc_decoration.js +321 -0
- data/app/assets/javascripts/abcjs/write/abc_dynamic_decoration.js +22 -1
- data/app/assets/javascripts/abcjs/write/abc_ending_element.js +31 -1
- data/app/assets/javascripts/abcjs/write/abc_engraver_controller.js +359 -0
- data/app/assets/javascripts/abcjs/write/abc_glyphs.js +119 -9
- data/app/assets/javascripts/abcjs/write/abc_layout.js +2 -2
- data/app/assets/javascripts/abcjs/write/abc_relative_element.js +106 -8
- data/app/assets/javascripts/abcjs/write/abc_renderer.js +754 -0
- data/app/assets/javascripts/abcjs/write/abc_staff_group_element.js +249 -9
- data/app/assets/javascripts/abcjs/write/abc_tempo_element.js +104 -0
- data/app/assets/javascripts/abcjs/write/abc_tie_element.js +69 -22
- data/app/assets/javascripts/abcjs/write/abc_triplet_element.js +77 -10
- data/app/assets/javascripts/abcjs/write/abc_voice_element.js +100 -8
- data/app/assets/javascripts/abcjs/write/abc_write.js +64 -68
- data/lib/abcjs-rails/version.rb +1 -1
- metadata +12 -4
@@ -22,40 +22,192 @@ if (!window.ABCJS)
|
|
22
22
|
if (!window.ABCJS.write)
|
23
23
|
window.ABCJS.write = {};
|
24
24
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
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
|
-
|
38
|
-
|
39
|
-
|
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
|
-
|
49
|
-
|
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
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
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
|
-
|
138
|
-
|
290
|
+
return [ startY, endY];
|
291
|
+
}
|
139
292
|
|
140
|
-
|
141
|
-
|
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
|
-
|
145
|
-
|
146
|
-
|
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
|
-
|
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
|
+
})();
|