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
@@ -35,8 +35,6 @@ if (!window.ABCJS.write)
35
35
  // Members:
36
36
  // staffs: an array of all the staves in this group. Each staff contains the following elements:
37
37
  // { top, bottom, highest, lowest, y }
38
- // stafflines: an array of the same length as staffs. It contains an integer with the number of lines.
39
- // TODO-PER: stafflines should actually be an element of staffs, I think.
40
38
  // voices: array of VoiceElement objects. This is mostly passed in, but the VoiceElement objects are modified here.
41
39
  //
42
40
  // spacingunits: number of relative x-units in the line. Used by the calling function to pass back in as the "spacing" input parameter.
@@ -54,18 +52,148 @@ if (!window.ABCJS.write)
54
52
  ABCJS.write.StaffGroupElement = function() {
55
53
  this.voices = [];
56
54
  this.staffs = [];
57
- this.stafflines = [];
55
+ };
56
+
57
+ ABCJS.write.StaffGroupElement.prototype.setLimit = function(member, voice) {
58
+ if (!voice.specialY[member]) return;
59
+ if (!voice.staff.specialY[member])
60
+ voice.staff.specialY[member] = voice.specialY[member];
61
+ else
62
+ voice.staff.specialY[member] = Math.max(voice.staff.specialY[member], voice.specialY[member]);
58
63
  };
59
64
 
60
65
  ABCJS.write.StaffGroupElement.prototype.addVoice = function (voice, staffnumber, stafflines) {
61
- this.voices[this.voices.length] = voice;
62
- if (!this.staffs[staffnumber]) {
63
- this.staffs[this.staffs.length] = {top:0, highest: 7, lowest: 7};
64
- this.stafflines[this.stafflines.length] = stafflines;
66
+ var voiceNum = this.voices.length;
67
+ this.voices[voiceNum] = voice;
68
+ if (this.staffs[staffnumber])
69
+ this.staffs[staffnumber].voices.push(voiceNum);
70
+ else {
71
+ // TODO-PER: how does the min/max change when stafflines is not 5?
72
+ this.staffs[this.staffs.length] = {
73
+ top: 10,
74
+ bottom: 2,
75
+ lines: stafflines,
76
+ voices: [voiceNum],
77
+ specialY: {
78
+ tempoHeightAbove: 0,
79
+ partHeightAbove: 0,
80
+ volumeHeightAbove: 0,
81
+ dynamicHeightAbove: 0,
82
+ endingHeightAbove: 0,
83
+ chordHeightAbove: 0,
84
+ lyricHeightAbove: 0,
85
+
86
+ lyricHeightBelow: 0,
87
+ chordHeightBelow: 0,
88
+ volumeHeightBelow: 0,
89
+ dynamicHeightBelow: 0
90
+ }
91
+ };
65
92
  }
66
93
  voice.staff = this.staffs[staffnumber];
67
94
  };
68
95
 
96
+ ABCJS.write.StaffGroupElement.prototype.setStaffLimits = function (voice) {
97
+ voice.staff.top = Math.max(voice.staff.top, voice.top);
98
+ voice.staff.bottom = Math.min(voice.staff.bottom, voice.bottom);
99
+ this.setLimit('tempoHeightAbove', voice);
100
+ this.setLimit('partHeightAbove', voice);
101
+ this.setLimit('volumeHeightAbove', voice);
102
+ this.setLimit('dynamicHeightAbove', voice);
103
+ this.setLimit('endingHeightAbove', voice);
104
+ this.setLimit('chordHeightAbove', voice);
105
+ this.setLimit('lyricHeightAbove', voice);
106
+ this.setLimit('lyricHeightBelow', voice);
107
+ this.setLimit('chordHeightBelow', voice);
108
+ this.setLimit('volumeHeightBelow', voice);
109
+ this.setLimit('dynamicHeightBelow', voice);
110
+ };
111
+
112
+ ABCJS.write.StaffGroupElement.prototype.setUpperAndLowerElements = function(renderer) {
113
+ // Each staff already has the top and bottom set, now we see if there are elements that are always on top and bottom, and resolve their pitch.
114
+ // Also, get the overall height of all the staves in this group.
115
+ var lastStaffBottom;
116
+ for (var i = 0; i < this.staffs.length; i++) {
117
+ var staff = this.staffs[i];
118
+ // the vertical order of elements that are above is: tempo, part, volume/dynamic, ending/chord, lyric
119
+ // the vertical order of elements that are below is: lyric, chord, volume/dynamic
120
+ var positionY = {
121
+ tempoHeightAbove: 0,
122
+ partHeightAbove: 0,
123
+ volumeHeightAbove: 0,
124
+ dynamicHeightAbove: 0,
125
+ endingHeightAbove: 0,
126
+ chordHeightAbove: 0,
127
+ lyricHeightAbove: 0,
128
+
129
+ lyricHeightBelow: 0,
130
+ chordHeightBelow: 0,
131
+ volumeHeightBelow: 0,
132
+ dynamicHeightBelow: 0
133
+ };
134
+
135
+ if (ABCJS.write.debugPlacement) {
136
+ staff.originalTop = staff.top; // This is just being stored for debugging purposes.
137
+ staff.originalBottom = staff.bottom; // This is just being stored for debugging purposes.
138
+ }
139
+
140
+ if (staff.specialY.lyricHeightAbove) { staff.top += staff.specialY.lyricHeightAbove; positionY.lyricHeightAbove = staff.top; }
141
+ if (staff.specialY.chordHeightAbove) { staff.top += staff.specialY.chordHeightAbove; positionY.chordHeightAbove = staff.top; }
142
+ if (staff.specialY.endingHeightAbove) {
143
+ if (staff.specialY.chordHeightAbove)
144
+ staff.top += 2;
145
+ else
146
+ staff.top += staff.specialY.endingHeightAbove;
147
+ positionY.endingHeightAbove = staff.top;
148
+ }
149
+ if (staff.specialY.dynamicHeightAbove && staff.specialY.volumeHeightAbove) {
150
+ staff.top += Math.max(staff.specialY.dynamicHeightAbove, staff.specialY.volumeHeightAbove);
151
+ positionY.dynamicHeightAbove = staff.top;
152
+ positionY.volumeHeightAbove = staff.top;
153
+ } else if (staff.specialY.dynamicHeightAbove) {
154
+ staff.top += staff.specialY.dynamicHeightAbove; positionY.dynamicHeightAbove = staff.top;
155
+ } else if (staff.specialY.volumeHeightAbove) { staff.top += staff.specialY.volumeHeightAbove; positionY.volumeHeightAbove = staff.top; }
156
+ if (staff.specialY.partHeightAbove) { staff.top += staff.specialY.partHeightAbove; positionY.partHeightAbove = staff.top; }
157
+ if (staff.specialY.tempoHeightAbove) { staff.top += staff.specialY.tempoHeightAbove; positionY.tempoHeightAbove = staff.top; }
158
+
159
+ if (staff.specialY.lyricHeightBelow) { positionY.lyricHeightBelow = staff.bottom; staff.bottom -= staff.specialY.lyricHeightBelow; }
160
+ if (staff.specialY.chordHeightBelow) { positionY.chordHeightBelow = staff.bottom; staff.bottom -= staff.specialY.chordHeightBelow; }
161
+ if (staff.specialY.volumeHeightBelow && staff.specialY.dynamicHeightBelow) {
162
+ positionY.volumeHeightBelow = staff.bottom;
163
+ positionY.dynamicHeightBelow = staff.bottom;
164
+ staff.bottom -= Math.max(staff.specialY.volumeHeightBelow, staff.specialY.dynamicHeightBelow);
165
+ } else if (staff.specialY.volumeHeightBelow) {
166
+ positionY.volumeHeightBelow = staff.bottom; staff.bottom -= staff.specialY.volumeHeightBelow;
167
+ } else if (staff.specialY.dynamicHeightBelow) {
168
+ positionY.dynamicHeightBelow = staff.bottom; staff.bottom -= staff.specialY.dynamicHeightBelow;
169
+ }
170
+
171
+ if (ABCJS.write.debugPlacement)
172
+ staff.positionY = positionY; // This is just being stored for debugging purposes.
173
+
174
+ for (var j = 0; j < staff.voices.length; j++) {
175
+ var voice = this.voices[staff.voices[j]];
176
+ voice.setUpperAndLowerElements(positionY);
177
+ }
178
+ // We might need a little space in between staves if the staves haven't been pushed far enough apart by notes or extra vertical stuff.
179
+ // Only try to put in extra space if this isn't the top staff.
180
+ if (lastStaffBottom !== undefined) {
181
+ var thisStaffTop = staff.top - 10;
182
+ var forcedSpacingBetween = lastStaffBottom + thisStaffTop;
183
+ var minSpacingInPitches = renderer.spacing.systemStaffSeparation/ABCJS.write.spacing.STEP;
184
+ var addedSpace = minSpacingInPitches - forcedSpacingBetween;
185
+ if (addedSpace > 0)
186
+ staff.top += addedSpace;
187
+ }
188
+ lastStaffBottom = 2 - staff.bottom; // the staff starts at position 2 and the bottom variable is negative. Therefore to find out how large the bottom is, we reverse the sign of the bottom, and add the 2 in.
189
+
190
+ // Now we need a little margin on the top, so we'll just throw that in.
191
+ //staff.top += 4;
192
+ //console.log("Staff Y: ",i,heightInPitches,staff.top,staff.bottom);
193
+ }
194
+ //console.log("Staff Height: ",heightInPitches,this.height);
195
+ };
196
+
69
197
  ABCJS.write.StaffGroupElement.prototype.finished = function() {
70
198
  for (var i=0;i<this.voices.length;i++) {
71
199
  if (!this.voices[i].layoutEnded()) return false;
@@ -73,21 +201,36 @@ ABCJS.write.StaffGroupElement.prototype.finished = function() {
73
201
  return true;
74
202
  };
75
203
 
204
+ <<<<<<< HEAD
205
+ ABCJS.write.StaffGroupElement.prototype.layout = function(spacing, renderer, debug) {
206
+ this.spacingunits = 0; // number of times we will have ended up using the spacing distance (as opposed to fixed width distances)
207
+ this.minspace = 1000; // a big number to start off with - used to find out what the smallest space between two notes is -- GD 2014.1.7
208
+ var x = renderer.padding.left;
209
+ =======
76
210
  ABCJS.write.StaffGroupElement.prototype.layout = function(spacing, controller, debug) {
77
211
  this.spacingunits = 0; // number of times we will have ended up using the spacing distance (as opposed to fixed width distances)
78
212
  this.minspace = 1000; // a big number to start off with - used to find out what the smallest space between two notes is -- GD 2014.1.7
79
213
  var x = controller.paddingleft*controller.scale;
214
+ >>>>>>> origin/master
80
215
 
81
216
  // find out how much space will be taken up by voice headers
82
217
  var voiceheaderw = 0;
83
218
  for (var i=0;i<this.voices.length;i++) {
84
219
  if(this.voices[i].header) {
85
- var t = controller.paper.text(100*controller.scale, -10*controller.scale, this.voices[i].header).attr({"font-size":12*controller.scale, "font-family":"serif", 'font-weight':'bold'}); // code duplicated below // don't scale this as we ask for the bbox
220
+ <<<<<<< HEAD
221
+ var size = renderer.getTextSize(this.voices[i].header, 'voicefont', '');
222
+ voiceheaderw = Math.max(voiceheaderw,size.width);
223
+ }
224
+ }
225
+ x=x+voiceheaderw*1.1; // When there is no voice header, 110% of 0 is 0
226
+ =======
227
+ var t = controller.renderText(100, this.y-10, this.voices[i].header, 'voicefont', ''); // code duplicated below // don't scale this as we ask for the bbox
86
228
  voiceheaderw = Math.max(voiceheaderw,t.getBBox().width);
87
229
  t.remove();
88
230
  }
89
231
  }
90
232
  x=x+voiceheaderw*(1/controller.scale)*1.1; // 10% of 0 is 0
233
+ >>>>>>> origin/master
91
234
  this.startx=x;
92
235
 
93
236
  var currentduration = 0;
@@ -124,12 +267,14 @@ ABCJS.write.StaffGroupElement.prototype.layout = function(spacing, controller, d
124
267
  spacingunit = 0; // number of spacingunits coming from the previously laid out element to this one
125
268
  var spacingduration = 0;
126
269
  for (i=0;i<currentvoices.length;i++) {
270
+ //console.log("greatest spacing unit", x, currentvoices[i].getNextX(), currentvoices[i].getSpacingUnits(), currentvoices[i].spacingduration);
127
271
  if (currentvoices[i].getNextX()>x) {
128
272
  x=currentvoices[i].getNextX();
129
273
  spacingunit=currentvoices[i].getSpacingUnits();
130
274
  spacingduration = currentvoices[i].spacingduration;
131
275
  }
132
276
  }
277
+ //console.log("new spacingunit", spacingunit, this.spacingunits, "="+(spacingunit+ this.spacingunits));
133
278
  this.spacingunits+=spacingunit;
134
279
  this.minspace = Math.min(this.minspace,spacingunit);
135
280
 
@@ -165,6 +310,7 @@ ABCJS.write.StaffGroupElement.prototype.layout = function(spacing, controller, d
165
310
  spacingunit=this.voices[i].getSpacingUnits();
166
311
  }
167
312
  }
313
+ //console.log("greatest remaining",spacingunit,x);
168
314
  this.spacingunits+=spacingunit;
169
315
  this.w = x;
170
316
 
@@ -173,6 +319,18 @@ ABCJS.write.StaffGroupElement.prototype.layout = function(spacing, controller, d
173
319
  }
174
320
  };
175
321
 
322
+ <<<<<<< HEAD
323
+ ABCJS.write.StaffGroupElement.prototype.calcHeight = function () {
324
+ // the height is calculated here in a parallel way to the drawing below in hopes that both of these functions will be modified together.
325
+ // TODO-PER: also add the space between staves. (That's systemStaffSeparation, which is the minimum distance between the staff LINES.)
326
+ var height = 0;
327
+ for (var i=0;i<this.voices.length;i++) {
328
+ var staff = this.voices[i].staff;
329
+ if (!this.voices[i].duplicate) {
330
+ height += staff.top;
331
+ if (staff.bottom < 0)
332
+ height += -staff.bottom;
333
+ =======
176
334
  ABCJS.write.StaffGroupElement.prototype.draw = function (renderer, y) {
177
335
 
178
336
  this.y = y;
@@ -192,10 +350,59 @@ ABCJS.write.StaffGroupElement.prototype.draw = function (renderer, y) {
192
350
  if (this.stafflines[i] === undefined)
193
351
  this.stafflines[i] = 5;
194
352
  renderer.printStave(this.startx, this.w, this.stafflines[i]);
353
+ >>>>>>> origin/master
195
354
  }
196
355
  }
197
- this.height = y-this.y;
356
+ return height;
357
+ };
198
358
 
359
+ <<<<<<< HEAD
360
+ ABCJS.write.StaffGroupElement.prototype.draw = function (renderer) {
361
+ // We enter this method with renderer.y pointing to the topmost coordinate that we're allowed to draw.
362
+ // All of the children that will be drawn have a relative "pitch" set, where zero is the first ledger line below the staff.
363
+ // renderer.y will be offset at the beginning of each staff by the amount required to make the relative pitch work.
364
+ // If there are multiple staves, then renderer.y will be incremented for each new staff.
365
+
366
+ var debugPrint;
367
+ var colorIndex;
368
+ if (ABCJS.write.debugPlacement) {
369
+ var colors = [ "rgba(207,27,36,0.4)", "rgba(168,214,80,0.4)", "rgba(110,161,224,0.4)", "rgba(191,119,218,0.4)", "rgba(195,30,151,0.4)",
370
+ "rgba(31,170,177,0.4)", "rgba(220,166,142,0.4)" ];
371
+ debugPrint = function(staff, key) {
372
+ if (staff.positionY[key]) {
373
+ //renderer.printHorizontalLine(50, renderer.calcY(staff.positionY[key]), key.substr(0, 4) + " " + Math.round(staff.positionY[key]));
374
+ var height = staff.specialY[key] * ABCJS.write.spacing.STEP;
375
+ renderer.printShadedBox(renderer.padding.left, renderer.calcY(staff.positionY[key]), renderer.controller.width, height,colors[colorIndex], key.substr(0, 4));
376
+ colorIndex += 1; if (colorIndex > 6) colorIndex = 0;
377
+ }
378
+ };
379
+ }
380
+
381
+ var startY = renderer.y; // So that it can be restored after we're done.
382
+ // Set the absolute Y position for each staff here, so the voice drawing below can just use if.
383
+ for (var j = 0; j < this.staffs.length; j++) {
384
+ var staff1 = this.staffs[j];
385
+ //renderer.printHorizontalLine(50, renderer.y, "start");
386
+ renderer.moveY(ABCJS.write.spacing.STEP, staff1.top);
387
+ staff1.absoluteY = renderer.y;
388
+ if (ABCJS.write.debugPlacement) {
389
+ colorIndex = 0;
390
+ renderer.printShadedBox(renderer.padding.left, renderer.calcY(staff1.originalTop), renderer.controller.width, renderer.calcY(staff1.originalBottom)-renderer.calcY(staff1.originalTop),"rgba(0,0,0,0.1)");
391
+ debugPrint(staff1, 'chordHeightAbove');
392
+ debugPrint(staff1, 'chordHeightBelow');
393
+ debugPrint(staff1, 'dynamicHeightAbove');
394
+ debugPrint(staff1, 'dynamicHeightBelow');
395
+ debugPrint(staff1, 'endingHeightAbove');
396
+ debugPrint(staff1, 'lyricHeightAbove');
397
+ debugPrint(staff1, 'lyricHeightBelow');
398
+ debugPrint(staff1, 'partHeightAbove');
399
+ debugPrint(staff1, 'tempoHeightAbove');
400
+ debugPrint(staff1, 'volumeHeightAbove');
401
+ debugPrint(staff1, 'volumeHeightBelow');
402
+ }
403
+ if (staff1.bottom < 0)
404
+ renderer.moveY(ABCJS.write.spacing.STEP, -staff1.bottom);
405
+ =======
199
406
  var bartop = 0;
200
407
  renderer.measureNumber = null;
201
408
  for (i=0;i<this.voices.length;i++) {
@@ -210,8 +417,35 @@ ABCJS.write.StaffGroupElement.prototype.draw = function (renderer, y) {
210
417
  renderer.y = this.staffs[this.staffs.length-1].y;
211
418
  var bottom = renderer.calcY(2);
212
419
  renderer.printStem(this.startx, 0.6, top, bottom);
420
+ >>>>>>> origin/master
213
421
  }
422
+ var topLine; // these are to connect multiple staves. We need to remember where they are.
423
+ var bottomLine;
214
424
 
425
+ <<<<<<< HEAD
426
+ var bartop = 0;
427
+ renderer.measureNumber = null;
428
+ for (var i=0;i<this.voices.length;i++) {
429
+ var staff = this.voices[i].staff;
430
+ renderer.y = staff.absoluteY;
431
+ //renderer.y = staff.y;
432
+ // offset for starting the counting at middle C
433
+ if (!this.voices[i].duplicate) {
434
+ // renderer.moveY(ABCJS.write.spacing.STEP, staff.top);
435
+ if (!topLine) topLine = renderer.calcY(10);
436
+ bottomLine = renderer.calcY(2);
437
+ if (staff.lines !== 0)
438
+ renderer.printStave(this.startx, this.w, staff.lines);
439
+ }
440
+ this.voices[i].draw(renderer, bartop);
441
+ if (!this.voices[i].duplicate) {
442
+ bartop = renderer.calcY(2); // This connects the bar lines between two different staves.
443
+ // if (staff.bottom < 0)
444
+ // renderer.moveY(ABCJS.write.spacing.STEP, -staff.bottom);
445
+ }
446
+ }
447
+ renderer.measureNumber = null;
448
+ =======
215
449
  // for (i=0;i<this.staffs.length;i++) {
216
450
  // if (this.stafflines[i] === 0) continue;
217
451
  // renderer.y = this.staffs[i].y;
@@ -220,6 +454,12 @@ ABCJS.write.StaffGroupElement.prototype.draw = function (renderer, y) {
220
454
  // this.stafflines[i] = 5;
221
455
  // renderer.printStave(this.startx,this.w, this.stafflines[i]);
222
456
  // }
457
+ >>>>>>> origin/master
223
458
 
459
+ // connect all the staves together with a vertical line
460
+ if (this.staffs.length>1) {
461
+ renderer.printStem(this.startx, 0.6, topLine, bottomLine);
462
+ }
463
+ renderer.y = startY;
224
464
  };
225
465
 
@@ -0,0 +1,104 @@
1
+ // abc_tempo_element.js: Definition of the TempoElement class.
2
+ // Copyright (C) 2014 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
+ var totalHeightInPitches = 5;
28
+
29
+ ABCJS.write.TempoElement = function(tempo) {
30
+ this.tempo = tempo;
31
+ this.tempoHeightAbove = totalHeightInPitches;
32
+ this.pitch = undefined; // This will be set later
33
+ };
34
+
35
+ ABCJS.write.TempoElement.prototype.setUpperAndLowerElements = function(positionY) { // TODO-PER: This might not be called.
36
+ this.pitch = positionY.tempoHeightAbove;
37
+ };
38
+
39
+ ABCJS.write.TempoElement.prototype.setX = function (x) {
40
+ this.x = x;
41
+ };
42
+
43
+ ABCJS.write.TempoElement.prototype.draw = function(renderer) {
44
+ var x = this.x;
45
+ if (this.pitch === undefined)
46
+ window.console.error("Tempo Element y-coordinate not set.");
47
+
48
+ var y = renderer.calcY(this.pitch);
49
+ var text;
50
+ if (this.tempo.preString) {
51
+ text = renderer.renderText(x, y, this.tempo.preString, 'tempofont', 'tempo', "start");
52
+ var preWidth = text.getBBox().width;
53
+ var charWidth = preWidth / this.tempo.preString.length; // Just get some average number to increase the spacing.
54
+ x += preWidth + charWidth;
55
+ }
56
+ if (this.tempo.duration) {
57
+ var temposcale = 0.75;
58
+ var tempopitch = this.pitch - totalHeightInPitches + 1; // The pitch we receive is the top of the allotted area: change that to practically the bottom.
59
+ var duration = this.tempo.duration[0]; // TODO when multiple durations
60
+ var abselem = new ABCJS.write.AbsoluteElement(this.tempo, duration, 1, 'tempo');
61
+ var durlog = Math.floor(Math.log(duration) / Math.log(2));
62
+ var dot = 0;
63
+ for (var tot = Math.pow(2, durlog), inc = tot / 2; tot < duration; dot++, tot += inc, inc /= 2);
64
+ var c = renderer.engraver.chartable.note[-durlog];
65
+ var flag = renderer.engraver.chartable.uflags[-durlog];
66
+ var temponote = renderer.engraver.createNoteHead(abselem, // TODO-PER: This seems late to be creating this element. Shouldn't it happen before draw?
67
+ c,
68
+ {verticalPos: tempopitch},
69
+ "up",
70
+ 0,
71
+ 0,
72
+ flag,
73
+ dot,
74
+ 0,
75
+ temposcale
76
+ );
77
+ abselem.addHead(temponote);
78
+ var stem;
79
+ if (duration < 1) {
80
+ var p1 = tempopitch + 1 / 3 * temposcale;
81
+ var p2 = tempopitch + 7 * temposcale;
82
+ var dx = temponote.dx + temponote.w;
83
+ var width = -0.6;
84
+ stem = new ABCJS.write.RelativeElement(null, dx, 0, p1, {"type": "stem", "pitch2": p2, linewidth: width});
85
+ stem.setX(x);
86
+ abselem.addExtra(stem);
87
+ }
88
+ abselem.x = x;
89
+ temponote.setX(x);
90
+ temponote.draw(renderer, x);
91
+ if (stem)
92
+ stem.draw(renderer, x);
93
+ x += (abselem.w + 5);
94
+ var str = "= " + this.tempo.bpm;
95
+ text = renderer.renderText(x, y, str, 'tempofont', 'tempo', "start");
96
+ var postWidth = text.getBBox().width;
97
+ var charWidth2 = postWidth / str.length; // Just get some average number to increase the spacing.
98
+ x += postWidth + charWidth2;
99
+ }
100
+ if (this.tempo.postString) {
101
+ renderer.renderText(x, y, this.tempo.postString, 'tempofont', 'tempo', "start");
102
+ }
103
+ };
104
+ })();