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
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 69dc7543800ee59c97f476146e4d23392cf201f0
4
- data.tar.gz: f36703aa7021da85d79ca7e8e287749f28db1b24
3
+ metadata.gz: fa42e9ce9d4ae382cdf01127928c52e1baaa8741
4
+ data.tar.gz: 146f81c567ee9aee005ceb00f5d29800a40fcb19
5
5
  SHA512:
6
- metadata.gz: ab12f67b09329ba8245b574c226519cb6fc8e202bf8cd9b6c6323662cedbfca851e1abde4b94d8d02961dd007aa19389043a7f7ed9dd6fc92ed6cb2bd4d0e39d
7
- data.tar.gz: 6228eac5b18e3cc8d6ce3b56545c29d8c12f741f321da6cf95a55a8e92994273dc4763931eba3836199f11b5625522c540f2211aa193151adb839cebe735f219
6
+ metadata.gz: 97b5c92b0832f98646268224d823fe88f7021dfbd90a1b8a5af0e2356ce39c63e58f2abfff49c363e6ef1cccdd44b555e9251e0e5263b603464f175434d89888
7
+ data.tar.gz: 4c060e9e01c5490e2b481636873881a0189c7748db272375e80e8c48e5066dc122223613b4ed39c4247c9572a91864f32cdc617992a0418a06dc1029485d4575
@@ -20,6 +20,10 @@ if (!window.ABCJS)
20
20
  window.ABCJS = {};
21
21
 
22
22
  (function() {
23
+ <<<<<<< HEAD
24
+ "use strict";
25
+ =======
26
+ >>>>>>> origin/master
23
27
 
24
28
  function hasClass(element, cls) {
25
29
  var elClass = element.getAttribute("class");
@@ -79,6 +83,10 @@ if (!window.ABCJS)
79
83
  if (options.showCursor) {
80
84
  cursor = $('<div class="cursor" style="position: absolute;"></div>');
81
85
  $(paper).append(cursor);
86
+ <<<<<<< HEAD
87
+ $(paper).css({ position: "relative" });
88
+ =======
89
+ >>>>>>> origin/master
82
90
  }
83
91
 
84
92
  stopNextTime = false;
@@ -107,7 +115,14 @@ if (!window.ABCJS)
107
115
  arr.push(hash[k]);
108
116
  }
109
117
  arr = arr.sort(function(a,b) {
110
- return a.time - b.time;
118
+ var diff = a.time - b.time;
119
+ // if the events have the same time, make sure a bar comes before a note
120
+ if (diff !== 0) {
121
+ return diff;
122
+ }
123
+ else {
124
+ return a.type === "bar" ? -1 : 1;
125
+ }
111
126
  });
112
127
  return arr;
113
128
  }
@@ -121,8 +136,18 @@ if (!window.ABCJS)
121
136
  for (var line=0;line<engraver.staffgroups.length; line++) {
122
137
  var group = engraver.staffgroups[line];
123
138
  var voices = group.voices;
139
+ <<<<<<< HEAD
140
+ var firstStaff = group.staffs[0];
141
+ var middleC = firstStaff.absoluteY;
142
+ var top = middleC - firstStaff.top*ABCJS.write.spacing.STEP;
143
+ var lastStaff = group.staffs[group.staffs.length-1];
144
+ middleC = lastStaff.absoluteY;
145
+ var bottom = middleC - lastStaff.bottom*ABCJS.write.spacing.STEP;
146
+ var height = bottom - top;
147
+ =======
124
148
  var top = group.y;
125
149
  var height = group.height;
150
+ >>>>>>> origin/master
126
151
  var maxVoiceTime = 0;
127
152
  // Put in the notes for all voices, then sort them, then remove duplicates
128
153
  for (var v = 0; v < voices.length; v++) {
@@ -140,7 +165,16 @@ if (!window.ABCJS)
140
165
  // If the note is tied on both sides it can just be ignored.
141
166
  } else {
142
167
  // the last note wasn't tied.
168
+ <<<<<<< HEAD
169
+ if (!eventHash["event"+voiceTime])
170
+ eventHash["event"+voiceTime] = { type: "event", time: voiceTime, top: top, height: height, left: element.x, width: element.w };
171
+ else {
172
+ // If there is more than one voice then two notes can fall at the same time. Usually they would be lined up in the same place, but if it is a whole rest, then it is placed funny. In any case, the left most element wins.
173
+ eventHash["event"+voiceTime].left = Math.min(eventHash["event"+voiceTime].left, element.x);
174
+ }
175
+ =======
143
176
  eventHash["event"+voiceTime] = { type: "event", time: voiceTime, top: top, height: height, left: element.x, width: element.w };
177
+ >>>>>>> origin/master
144
178
  if (isTiedToNext)
145
179
  isTiedState = true;
146
180
  }
@@ -184,7 +218,13 @@ if (!window.ABCJS)
184
218
  if (currentNote.type === "bar") {
185
219
  if (options.hideFinishedMeasures)
186
220
  processMeasureHider(currentNote.lineNum, currentNote.measureNum);
221
+ <<<<<<< HEAD
222
+ if (timingEvents.length > 0)
223
+ return timingEvents[0].time / beatLength;
224
+ return 0;
225
+ =======
187
226
  return processShowCursor();
227
+ >>>>>>> origin/master
188
228
  }
189
229
  if (options.showCursor)
190
230
  cursor.css({ left: currentNote.left + "px", top: currentNote.top + "px", width: currentNote.width + "px", height: currentNote.height + "px" });
@@ -156,8 +156,13 @@ if (!window.ABCJS)
156
156
  /* jshint -W064 */ var paper = Raphael(div, width, 400); /* jshint +W064 */
157
157
  if (engraverParams === undefined)
158
158
  engraverParams = {};
159
+ <<<<<<< HEAD
160
+ var engraver_controller = new ABCJS.write.EngraverController(paper, engraverParams);
161
+ engraver_controller.engraveABC(tune);
162
+ =======
159
163
  var engraver_controller = new ABCJS.write.Printer(paper, engraverParams);
160
164
  engraver_controller.printABC(tune);
165
+ >>>>>>> origin/master
161
166
  tune.engraver = engraver_controller;
162
167
  }
163
168
 
@@ -101,7 +101,7 @@ window.ABCJS.data.Tune = function() {
101
101
  this.lineNum = 0;
102
102
  };
103
103
 
104
- this.cleanUp = function(defWidth, defLength, barsperstaff, staffnonote) {
104
+ this.cleanUp = function(defWidth, defLength, barsperstaff, staffnonote, currSlur) {
105
105
  this.closeLine(); // Close the last line.
106
106
 
107
107
  // Remove any blank lines
@@ -211,7 +211,6 @@ window.ABCJS.data.Tune = function() {
211
211
  }
212
212
 
213
213
  function cleanUpSlursInLine(line) {
214
- var currSlur = [];
215
214
  var x;
216
215
  // var lyr = null; // TODO-PER: debugging.
217
216
 
@@ -225,7 +224,7 @@ window.ABCJS.data.Tune = function() {
225
224
  }
226
225
  }
227
226
  if (currSlur[chordPos] === undefined) {
228
- var offNum = chordPos*100;
227
+ var offNum = chordPos*100+1;
229
228
  window.ABCJS.parse.each(obj.endSlur, function(x) { if (offNum === x) --offNum; });
230
229
  currSlur[chordPos] = [offNum];
231
230
  }
@@ -399,6 +398,8 @@ window.ABCJS.data.Tune = function() {
399
398
  delete this.potentialStartBeam;
400
399
  delete this.potentialEndBeam;
401
400
  delete this.vskipPending;
401
+
402
+ return currSlur;
402
403
  };
403
404
 
404
405
  this.reset();
@@ -241,8 +241,13 @@ window.ABCJS.Editor.prototype.renderTune = function(abc, params, div) {
241
241
  abcParser.parse(tunebook.tunes[0].abc, params); //TODO handle multiple tunes
242
242
  var tune = abcParser.getTune();
243
243
  var paper = Raphael(div, 800, 400);
244
+ <<<<<<< HEAD
245
+ var engraver_controller = new ABCJS.write.EngraverController(paper, this.engraverparams);
246
+ engraver_controller.engraveABC(tune);
247
+ =======
244
248
  var engraver_controller = new ABCJS.write.Printer(paper, this.engraverparams);
245
249
  engraver_controller.printABC(tune);
250
+ >>>>>>> origin/master
246
251
  };
247
252
 
248
253
  window.ABCJS.Editor.prototype.modelChanged = function() {
@@ -259,8 +264,13 @@ window.ABCJS.Editor.prototype.modelChanged = function() {
259
264
  this.timerId = null;
260
265
  this.div.innerHTML = "";
261
266
  var paper = Raphael(this.div, 800, 400);
267
+ <<<<<<< HEAD
268
+ this.engraver_controller = new ABCJS.write.EngraverController(paper, this.engraverparams);
269
+ this.engraver_controller.engraveABC(this.tunes);
270
+ =======
262
271
  this.engraver_controller = new ABCJS.write.Printer(paper, this.engraverparams);
263
272
  this.engraver_controller.printABC(this.tunes);
273
+ >>>>>>> origin/master
264
274
  this.tunes[0].engraver = this.engraver_controller; // TODO-PER: We actually want an output object for each tune, not the entire controller. When refactoring, don't save data in the controller.
265
275
  if (ABCJS.midi.MidiWriter && this.mididiv) {
266
276
  if (this.mididiv !== this.div)
@@ -23,6 +23,7 @@ if (!window.ABCJS.parse)
23
23
  window.ABCJS.parse = {};
24
24
 
25
25
  window.ABCJS.parse.Parse = function() {
26
+ "use strict";
26
27
  var tune = new window.ABCJS.data.Tune();
27
28
  var tokenizer = new window.ABCJS.parse.tokenizer();
28
29
 
@@ -30,6 +31,16 @@ window.ABCJS.parse.Parse = function() {
30
31
  return tune;
31
32
  };
32
33
 
34
+ function addPositioning(el, type, value) {
35
+ if (!el.positioning) el.positioning = {};
36
+ el.positioning[type] = value;
37
+ }
38
+
39
+ function addFont(el, type, value) {
40
+ if (!el.fonts) el.fonts = {};
41
+ el.fonts[type] = value;
42
+ }
43
+
33
44
  var multilineVars = {
34
45
  reset: function() {
35
46
  for (var property in this) {
@@ -62,6 +73,39 @@ window.ABCJS.parse.Parse = function() {
62
73
  this.inEnding = false;
63
74
  this.inTie = false;
64
75
  this.inTieChord = {};
76
+ this.vocalPosition = "auto";
77
+ this.dynamicPosition = "auto";
78
+ this.chordPosition = "auto";
79
+ this.ornamentPosition = "auto";
80
+ this.volumePosition = "auto";
81
+ this.openSlurs = [];
82
+ },
83
+ differentFont: function(type, defaultFonts) {
84
+ if (this[type].decoration !== defaultFonts[type].decoration) return true;
85
+ if (this[type].face !== defaultFonts[type].face) return true;
86
+ if (this[type].size !== defaultFonts[type].size) return true;
87
+ if (this[type].style !== defaultFonts[type].style) return true;
88
+ if (this[type].weight !== defaultFonts[type].weight) return true;
89
+ return false;
90
+ },
91
+ addFormattingOptions: function(el, defaultFonts, elType) {
92
+ if (elType === 'note') {
93
+ if (this.vocalPosition !== 'auto') addPositioning(el, 'vocalPosition', this.vocalPosition);
94
+ if (this.dynamicPosition !== 'auto') addPositioning(el, 'dynamicPosition', this.dynamicPosition);
95
+ if (this.chordPosition !== 'auto') addPositioning(el, 'chordPosition', this.chordPosition);
96
+ if (this.ornamentPosition !== 'auto') addPositioning(el, 'ornamentPosition', this.ornamentPosition);
97
+ if (this.volumePosition !== 'auto') addPositioning(el, 'volumePosition', this.volumePosition);
98
+ if (this.differentFont("annotationfont", defaultFonts)) addFont(el, 'annotationfont', this.annotationfont);
99
+ if (this.differentFont("gchordfont", defaultFonts)) addFont(el, 'gchordfont', this.gchordfont);
100
+ if (this.differentFont("vocalfont", defaultFonts)) addFont(el, 'vocalfont', this.vocalfont);
101
+ } else if (elType === 'bar') {
102
+ if (this.dynamicPosition !== 'auto') addPositioning(el, 'dynamicPosition', this.dynamicPosition);
103
+ if (this.chordPosition !== 'auto') addPositioning(el, 'chordPosition', this.chordPosition);
104
+ if (this.ornamentPosition !== 'auto') addPositioning(el, 'ornamentPosition', this.ornamentPosition);
105
+ if (this.volumePosition !== 'auto') addPositioning(el, 'volumePosition', this.volumePosition);
106
+ if (this.differentFont("measurefont", defaultFonts)) addFont(el, 'measurefont', this.measurefont);
107
+ if (this.differentFont("repeatfont", defaultFonts)) addFont(el, 'repeatfont', this.repeatfont);
108
+ }
65
109
  }
66
110
  };
67
111
 
@@ -79,6 +123,7 @@ window.ABCJS.parse.Parse = function() {
79
123
  };
80
124
 
81
125
  var warn = function(str, line, col_num) {
126
+ if (!line) line = " ";
82
127
  var bad_char = line.charAt(col_num);
83
128
  if (bad_char === ' ')
84
129
  bad_char = "SPACE";
@@ -146,14 +191,20 @@ window.ABCJS.parse.Parse = function() {
146
191
  var legalAccents = [ "trill", "lowermordent", "uppermordent", "mordent", "pralltriller", "accent",
147
192
  "fermata", "invertedfermata", "tenuto", "0", "1", "2", "3", "4", "5", "+", "wedge",
148
193
  "open", "thumb", "snap", "turn", "roll", "breath", "shortphrase", "mediumphrase", "longphrase",
149
- "segno", "coda", "D.S.", "D.C.", "fine", "crescendo(", "crescendo)", "diminuendo(", "diminuendo)",
150
- "p", "pp", "f", "ff", "mf", "mp", "ppp", "pppp", "fff", "ffff", "sfz", "repeatbar", "repeatbar2", "slide",
194
+ "segno", "coda", "D.S.", "D.C.", "fine",
195
+ "slide", "^", "marcato",
151
196
  "upbow", "downbow", "/", "//", "///", "////", "trem1", "trem2", "trem3", "trem4",
152
197
  "turnx", "invertedturn", "invertedturnx", "trill(", "trill)", "arpeggio", "xstem", "mark", "umarcato",
153
198
  "style=normal", "style=harmonic", "style=rhythm", "style=x"
154
199
  ];
155
- var accentPsuedonyms = [ ["<", "accent"], [">", "accent"], ["tr", "trill"], ["<(", "crescendo("], ["<)", "crescendo)"],
156
- [">(", "diminuendo("], [">)", "diminuendo)"], ["plus", "+"], [ "emphasis", "accent"] ];
200
+ var volumeDecorations = [ "p", "pp", "f", "ff", "mf", "mp", "ppp", "pppp", "fff", "ffff", "sfz" ];
201
+ var dynamicDecorations = ["crescendo(", "crescendo)", "diminuendo(", "diminuendo)"];
202
+
203
+ var accentPseudonyms = [ ["<", "accent"], [">", "accent"], ["tr", "trill"],
204
+ ["plus", "+"], [ "emphasis", "accent"],
205
+ [ "^", "umarcato" ], [ "marcato", "umarcato" ] ];
206
+ var accentDynamicPseudonyms = [ ["<(", "crescendo("], ["<)", "crescendo)"],
207
+ [">(", "diminuendo("], [">)", "diminuendo)"] ];
157
208
  var letter_to_accent = function(line, i)
158
209
  {
159
210
  var macro = multilineVars.macros[line.charAt(i)];
@@ -167,7 +218,19 @@ window.ABCJS.parse.Parse = function() {
167
218
  return (macro === acc);
168
219
  }))
169
220
  return [ 1, macro ];
170
- else {
221
+ else if (window.ABCJS.parse.detect(volumeDecorations, function(acc) {
222
+ return (macro === acc);
223
+ })) {
224
+ if (multilineVars.volumePosition === 'hidden')
225
+ macro = "";
226
+ return [1, macro];
227
+ } else if (window.ABCJS.parse.detect(dynamicDecorations, function(acc) {
228
+ if (multilineVars.dynamicPosition === 'hidden')
229
+ macro = "";
230
+ return (macro === acc);
231
+ })) {
232
+ return [1, macro];
233
+ } else {
171
234
  if (!window.ABCJS.parse.detect(multilineVars.ignoredDecorations, function(dec) {
172
235
  return (macro === dec);
173
236
  }))
@@ -191,8 +254,22 @@ window.ABCJS.parse.Parse = function() {
191
254
  return (ret[1] === acc);
192
255
  }))
193
256
  return ret;
257
+ if (window.ABCJS.parse.detect(volumeDecorations, function(acc) {
258
+ return (ret[1] === acc);
259
+ })) {
260
+ if (multilineVars.volumePosition === 'hidden' )
261
+ ret[1] = '';
262
+ return ret;
263
+ }
264
+ if (window.ABCJS.parse.detect(dynamicDecorations, function(acc) {
265
+ return (ret[1] === acc);
266
+ })) {
267
+ if (multilineVars.dynamicPosition === 'hidden' )
268
+ ret[1] = '';
269
+ return ret;
270
+ }
194
271
 
195
- if (window.ABCJS.parse.detect(accentPsuedonyms, function(acc) {
272
+ if (window.ABCJS.parse.detect(accentPseudonyms, function(acc) {
196
273
  if (ret[1] === acc[0]) {
197
274
  ret[1] = acc[1];
198
275
  return true;
@@ -201,6 +278,17 @@ window.ABCJS.parse.Parse = function() {
201
278
  }))
202
279
  return ret;
203
280
 
281
+ if (window.ABCJS.parse.detect(accentDynamicPseudonyms, function(acc) {
282
+ if (ret[1] === acc[0]) {
283
+ ret[1] = acc[1];
284
+ return true;
285
+ } else
286
+ return false;
287
+ })) {
288
+ if (multilineVars.dynamicPosition === 'hidden' )
289
+ ret[1] = '';
290
+ return ret;
291
+ }
204
292
  // We didn't find the accent in the list, so consume the space, but don't return an accent.
205
293
  // Although it is possible that ! was used as a line break, so accept that.
206
294
  if (line.charAt(i) === '!' && (ret[0] === 1 || line.charAt(i+ret[0]-1) !== '!'))
@@ -319,7 +407,7 @@ window.ABCJS.parse.Parse = function() {
319
407
  };
320
408
 
321
409
  var addWords = function(line, words) {
322
- if (!line) { warn("Can't add words before the first line of mulsic", line, 0); return; }
410
+ if (!line) { warn("Can't add words before the first line of music", line, 0); return; }
323
411
  words = window.ABCJS.parse.strip(words);
324
412
  if (words.charAt(words.length-1) !== '-')
325
413
  words = words + ' '; // Just makes it easier to parse below, since every word has a divider after it.
@@ -396,7 +484,7 @@ window.ABCJS.parse.Parse = function() {
396
484
 
397
485
  var addSymbols = function(line, words) {
398
486
  // TODO-PER: Currently copied from w: line. This needs to be read as symbols instead.
399
- if (!line) { warn("Can't add symbols before the first line of mulsic", line, 0); return; }
487
+ if (!line) { warn("Can't add symbols before the first line of music", line, 0); return; }
400
488
  words = window.ABCJS.parse.strip(words);
401
489
  if (words.charAt(words.length-1) !== '-')
402
490
  words = words + ' '; // Just makes it easier to parse below, since every word has a divider after it.
@@ -786,6 +874,8 @@ window.ABCJS.parse.Parse = function() {
786
874
  }
787
875
  var note = getCoreNote(gra[1], ii, {}, false);
788
876
  if (note !== null) {
877
+ // The grace note durations should not be affected by the default length: they should be based on 1/16, so if that isn't the default, then multiply here.
878
+ note.duration = note.duration / (multilineVars.default_length * 8);
789
879
  if (acciaccatura)
790
880
  note.acciaccatura = true;
791
881
  gracenotes.push(note);
@@ -1011,9 +1101,13 @@ window.ABCJS.parse.Parse = function() {
1011
1101
  if (i + 1 < line.length)
1012
1102
  startNewLine(); // There was a ! in the middle of the line. Start a new line if there is anything after it.
1013
1103
  } else if (ret[1].length > 0) {
1014
- if (el.decoration === undefined)
1015
- el.decoration = [];
1016
- el.decoration.push(ret[1]);
1104
+ if (ret[1].indexOf("style=") === 0) {
1105
+ el.style = ret[1].substr(6);
1106
+ } else {
1107
+ if (el.decoration === undefined)
1108
+ el.decoration = [];
1109
+ el.decoration.push(ret[1]);
1110
+ }
1017
1111
  }
1018
1112
  i += ret[0];
1019
1113
  } else {
@@ -1035,6 +1129,7 @@ window.ABCJS.parse.Parse = function() {
1035
1129
  // Attach the grace note to an invisible note
1036
1130
  el.rest = { type: 'spacer' };
1037
1131
  el.duration = 0.125; // TODO-PER: I don't think the duration of this matters much, but figure out if it does.
1132
+ multilineVars.addFormattingOptions(el, tune.formatting, 'note');
1038
1133
  tune.appendElement('note', startOfLine+i, startOfLine+i+ret[0], el);
1039
1134
  multilineVars.measureNotEmpty = true;
1040
1135
  el = {};
@@ -1068,6 +1163,7 @@ window.ABCJS.parse.Parse = function() {
1068
1163
  if (multilineVars.barNumbers && multilineVars.currBarNumber % multilineVars.barNumbers === 0)
1069
1164
  multilineVars.barNumOnNextNote = multilineVars.currBarNumber;
1070
1165
  }
1166
+ multilineVars.addFormattingOptions(el, tune.formatting, 'bar');
1071
1167
  tune.appendElement('bar', startOfLine+i, startOfLine+i+ret[0], bar);
1072
1168
  multilineVars.measureNotEmpty = false;
1073
1169
  el = {};
@@ -1221,6 +1317,7 @@ window.ABCJS.parse.Parse = function() {
1221
1317
  el.barNumber = multilineVars.barNumOnNextNote;
1222
1318
  multilineVars.barNumOnNextNote = null;
1223
1319
  }
1320
+ multilineVars.addFormattingOptions(el, tune.formatting, 'note');
1224
1321
  tune.appendElement('note', startOfLine+i, startOfLine+i, el);
1225
1322
  multilineVars.measureNotEmpty = true;
1226
1323
  el = {};
@@ -1293,6 +1390,7 @@ window.ABCJS.parse.Parse = function() {
1293
1390
  el.barNumber = multilineVars.barNumOnNextNote;
1294
1391
  multilineVars.barNumOnNextNote = null;
1295
1392
  }
1393
+ multilineVars.addFormattingOptions(el, tune.formatting, 'note');
1296
1394
  tune.appendElement('note', startOfLine+startI, startOfLine+i, el);
1297
1395
  multilineVars.measureNotEmpty = true;
1298
1396
  el = {};
@@ -1329,8 +1427,10 @@ window.ABCJS.parse.Parse = function() {
1329
1427
  // switches.header_only : stop parsing when the header is finished
1330
1428
  // switches.stop_on_warning : stop at the first warning encountered.
1331
1429
  // switches.print: format for the page instead of the browser.
1430
+ // switches.format: a hash of the desired formatting commands.
1431
+ if (!switches) switches = {};
1332
1432
  tune.reset();
1333
- if (switches && switches.print)
1433
+ if (switches.print)
1334
1434
  tune.media = 'print';
1335
1435
  multilineVars.reset();
1336
1436
  header.reset(tokenizer, warn, multilineVars, tune);
@@ -1350,13 +1450,14 @@ window.ABCJS.parse.Parse = function() {
1350
1450
  if (window.ABCJS.parse.last(lines).length === 0) // remove the blank line we added above.
1351
1451
  lines.pop();
1352
1452
  try {
1453
+ if (switches.format) {
1454
+ window.ABCJS.parse.parseDirective.globalFormatting(switches.format);
1455
+ }
1353
1456
  window.ABCJS.parse.each(lines, function(line) {
1354
- if (switches) {
1355
- if (switches.header_only && multilineVars.is_in_header === false)
1356
- throw "normal_abort";
1357
- if (switches.stop_on_warning && multilineVars.warnings)
1358
- throw "normal_abort";
1359
- }
1457
+ if (switches.header_only && multilineVars.is_in_header === false)
1458
+ throw "normal_abort";
1459
+ if (switches.stop_on_warning && multilineVars.warnings)
1460
+ throw "normal_abort";
1360
1461
  if (multilineVars.is_in_history) {
1361
1462
  if (line.charAt(1) === ':') {
1362
1463
  multilineVars.is_in_history = false;
@@ -1398,7 +1499,7 @@ window.ABCJS.parse.Parse = function() {
1398
1499
  ph = pl;
1399
1500
  pl = x;
1400
1501
  }
1401
- tune.cleanUp(pl, ph, multilineVars.barsperstaff, multilineVars.staffnonote);
1502
+ multilineVars.openSlurs = tune.cleanUp(pl, ph, multilineVars.barsperstaff, multilineVars.staffnonote, multilineVars.openSlurs);
1402
1503
  } catch (err) {
1403
1504
  if (err !== "normal_abort")
1404
1505
  throw err;
@@ -9,6 +9,7 @@ if (!window.ABCJS.parse)
9
9
  window.ABCJS.parse.parseDirective = {};
10
10
 
11
11
  (function() {
12
+ "use strict";
12
13
  var tokenizer;
13
14
  var warn;
14
15
  var multilineVars;
@@ -18,6 +19,377 @@ window.ABCJS.parse.parseDirective = {};
18
19
  warn = warn_;
19
20
  multilineVars = multilineVars_;
20
21
  tune = tune_;
22
+ initializeFonts();
23
+ };
24
+
25
+ function initializeFonts() {
26
+ multilineVars.annotationfont = { face: "Helvetica", size: 12, weight: "normal", style: "normal", decoration: "none" };
27
+ multilineVars.gchordfont = { face: "Helvetica", size: 12, weight: "normal", style: "normal", decoration: "none" };
28
+ multilineVars.historyfont = { face: "\"Times New Roman\"", size: 16, weight: "normal", style: "normal", decoration: "none" };
29
+ multilineVars.infofont = { face: "\"Times New Roman\"", size: 14, weight: "normal", style: "italic", decoration: "none" };
30
+ multilineVars.measurefont = { face: "\"Times New Roman\"", size: 14, weight: "normal", style: "italic", decoration: "none" };
31
+ multilineVars.partsfont = { face: "\"Times New Roman\"", size: 15, weight: "normal", style: "normal", decoration: "none" };
32
+ multilineVars.repeatfont = { face: "\"Times New Roman\"", size: 13, weight: "normal", style: "normal", decoration: "none" };
33
+ multilineVars.textfont = { face: "\"Times New Roman\"", size: 16, weight: "normal", style: "normal", decoration: "none" };
34
+ multilineVars.vocalfont = { face: "\"Times New Roman\"", size: 13, weight: "bold", style: "normal", decoration: "none" };
35
+ multilineVars.wordsfont = { face: "\"Times New Roman\"", size: 16, weight: "normal", style: "normal", decoration: "none" };
36
+
37
+ <<<<<<< HEAD
38
+ // These fonts are global for the entire tune.
39
+ =======
40
+ >>>>>>> origin/master
41
+ tune.formatting.composerfont = { face: "\"Times New Roman\"", size: 14, weight: "normal", style: "italic", decoration: "none" };
42
+ tune.formatting.subtitlefont = { face: "\"Times New Roman\"", size: 16, weight: "normal", style: "normal", decoration: "none" };
43
+ tune.formatting.tempofont = { face: "\"Times New Roman\"", size: 15, weight: "bold", style: "normal", decoration: "none" };
44
+ tune.formatting.titlefont = { face: "\"Times New Roman\"", size: 20, weight: "normal", style: "normal", decoration: "none" };
45
+ tune.formatting.footerfont = { face: "\"Times New Roman\"", size: 12, weight: "normal", style: "normal", decoration: "none" };
46
+ tune.formatting.headerfont = { face: "\"Times New Roman\"", size: 12, weight: "normal", style: "normal", decoration: "none" };
47
+ tune.formatting.voicefont = { face: "\"Times New Roman\"", size: 13, weight: "bold", style: "normal", decoration: "none" };
48
+ <<<<<<< HEAD
49
+
50
+ // these are the default fonts for these element types. In the printer, these fonts might change as the tune progresses.
51
+ tune.formatting.annotationfont = multilineVars.annotationfont;
52
+ tune.formatting.gchordfont = multilineVars.gchordfont;
53
+ tune.formatting.historyfont = multilineVars.historyfont;
54
+ tune.formatting.infofont = multilineVars.infofont;
55
+ tune.formatting.measurefont = multilineVars.measurefont;
56
+ tune.formatting.partsfont = multilineVars.partsfont;
57
+ tune.formatting.repeatfont = multilineVars.repeatfont;
58
+ tune.formatting.textfont = multilineVars.textfont;
59
+ tune.formatting.vocalfont = multilineVars.vocalfont;
60
+ tune.formatting.wordsfont = multilineVars.wordsfont;
61
+ =======
62
+ >>>>>>> origin/master
63
+ }
64
+
65
+ var fontTypeCanHaveBox = { gchordfont: true, measurefont: true, partsfont: true };
66
+
67
+ var fontTranslation = function(fontFace) {
68
+ // This translates Postscript fonts for a web alternative.
69
+ // Note that the postscript fonts contain italic and bold info in them, so what is returned is a hash.
70
+
71
+ switch (fontFace) {
72
+ case "Arial-Italic":
73
+ return { face: "Arial", weight: "normal", style: "italic", decoration: "none" };
74
+ case "Arial-Bold":
75
+ return { face: "Arial", weight: "bold", style: "normal", decoration: "none" };
76
+ case "Bookman-Demi":
77
+ return { face: "Bookman,serif", weight: "bold", style: "normal", decoration: "none" };
78
+ case "Bookman-DemiItalic":
79
+ return { face: "Bookman,serif", weight: "bold", style: "italic", decoration: "none" };
80
+ case "Bookman-Light":
81
+ return { face: "Bookman,serif", weight: "normal", style: "normal", decoration: "none" };
82
+ case "Bookman-LightItalic":
83
+ return { face: "Bookman,serif", weight: "normal", style: "italic", decoration: "none" };
84
+ case "Courier":
85
+ return { face: "\"Courier New\"", weight: "normal", style: "normal", decoration: "none" };
86
+ case "Courier-Oblique":
87
+ return { face: "\"Courier New\"", weight: "normal", style: "italic", decoration: "none" };
88
+ case "Courier-Bold":
89
+ return { face: "\"Courier New\"", weight: "bold", style: "normal", decoration: "none" };
90
+ case "Courier-BoldOblique":
91
+ return { face: "\"Courier New\"", weight: "bold", style: "italic", decoration: "none" };
92
+ case "AvantGarde-Book":
93
+ return { face: "AvantGarde,Arial", weight: "normal", style: "normal", decoration: "none" };
94
+ case "AvantGarde-BookOblique":
95
+ return { face: "AvantGarde,Arial", weight: "normal", style: "italic", decoration: "none" };
96
+ case "AvantGarde-Demi":
97
+ case "Avant-Garde-Demi":
98
+ return { face: "AvantGarde,Arial", weight: "bold", style: "normal", decoration: "none" };
99
+ case "AvantGarde-DemiOblique":
100
+ return { face: "AvantGarde,Arial", weight: "bold", style: "italic", decoration: "none" };
101
+ case "Helvetica-Oblique":
102
+ return { face: "Helvetica", weight: "normal", style: "italic", decoration: "none" };
103
+ case "Helvetica-Bold":
104
+ return { face: "Helvetica", weight: "bold", style: "normal", decoration: "none" };
105
+ case "Helvetica-BoldOblique":
106
+ return { face: "Helvetica", weight: "bold", style: "italic", decoration: "none" };
107
+ case "Helvetica-Narrow":
108
+ return { face: "\"Helvetica Narrow\",Helvetica", weight: "normal", style: "normal", decoration: "none" };
109
+ case "Helvetica-Narrow-Oblique":
110
+ return { face: "\"Helvetica Narrow\",Helvetica", weight: "normal", style: "italic", decoration: "none" };
111
+ case "Helvetica-Narrow-Bold":
112
+ return { face: "\"Helvetica Narrow\",Helvetica", weight: "bold", style: "normal", decoration: "none" };
113
+ case "Helvetica-Narrow-BoldOblique":
114
+ return { face: "\"Helvetica Narrow\",Helvetica", weight: "bold", style: "italic", decoration: "none" };
115
+ case "Palatino-Roman":
116
+ return { face: "Palatino", weight: "normal", style: "normal", decoration: "none" };
117
+ case "Palatino-Italic":
118
+ return { face: "Palatino", weight: "normal", style: "italic", decoration: "none" };
119
+ case "Palatino-Bold":
120
+ return { face: "Palatino", weight: "bold", style: "normal", decoration: "none" };
121
+ case "Palatino-BoldItalic":
122
+ return { face: "Palatino", weight: "bold", style: "italic", decoration: "none" };
123
+ case "NewCenturySchlbk-Roman":
124
+ return { face: "\"New Century\",serif", weight: "normal", style: "normal", decoration: "none" };
125
+ case "NewCenturySchlbk-Italic":
126
+ return { face: "\"New Century\",serif", weight: "normal", style: "italic", decoration: "none" };
127
+ case "NewCenturySchlbk-Bold":
128
+ return { face: "\"New Century\",serif", weight: "bold", style: "normal", decoration: "none" };
129
+ case "NewCenturySchlbk-BoldItalic":
130
+ return { face: "\"New Century\",serif", weight: "bold", style: "italic", decoration: "none" };
131
+ case "Times":
132
+ case "Times-Roman":
133
+ case "Times-Narrow":
134
+ case "Times-Courier":
135
+ case "Times-New-Roman":
136
+ return { face: "\"Times New Roman\"", weight: "normal", style: "normal", decoration: "none" };
137
+ case "Times-Italic":
138
+ case "Times-Italics":
139
+ return { face: "\"Times New Roman\"", weight: "normal", style: "italic", decoration: "none" };
140
+ case "Times-Bold":
141
+ return { face: "\"Times New Roman\"", weight: "bold", style: "normal", decoration: "none" };
142
+ case "Times-BoldItalic":
143
+ return { face: "\"Times New Roman\"", weight: "bold", style: "italic", decoration: "none" };
144
+ case "ZapfChancery-MediumItalic":
145
+ return { face: "\"Zapf Chancery\",cursive,serif", weight: "normal", style: "normal", decoration: "none" };
146
+ default:
147
+ return null;
148
+ }
149
+ };
150
+
151
+ var getFontParameter = function(tokens, currentSetting, str, position, cmd) {
152
+ // Every font parameter has the following format:
153
+ // <face> <utf8> <size> <modifiers> <box>
154
+ // Where:
155
+ // face: either a standard web font name, or a postscript font, enumerated in fontTranslation. This could also be an * or be missing if the face shouldn't change.
156
+ // utf8: This is optional, and specifies utf8. That's all that is supported so the field is just silently ignored.
157
+ // size: The size, in pixels. This may be omitted if the size is not changing.
158
+ // modifiers: zero or more of "bold", "italic", "underline"
159
+ // box: Only applies to the measure numbers, gchords, and the parts. If present, then a box is drawn around the characters.
160
+ // If face is present, then all the modifiers are cleared. If face is absent, then the modifiers are illegal.
161
+ // The face can be a single word, a set of words separated by hyphens, or a quoted string.
162
+ //
163
+ // So, in practicality, there are three types of font definitions: a number only, an asterisk and a number only, or the full definition (with an optional size).
164
+ function processNumberOnly() {
165
+ var size = parseInt(tokens[0].token);
166
+ tokens.shift();
167
+ if (!currentSetting) {
168
+ warn("Can't set just the size of the font since there is no default value.", str, position);
169
+ return { face: "\"Times New Roman\"", weight: "normal", style: "normal", decoration: "none", size: size};
170
+ }
171
+ if (tokens.length === 0) {
172
+ return { face: currentSetting.face, weight: currentSetting.weight, style: currentSetting.style, decoration: currentSetting.decoration, size: size};
173
+ }
174
+ if (tokens.length === 1 && tokens[0].token === "box" && fontTypeCanHaveBox[cmd])
175
+ return { face: currentSetting.face, weight: currentSetting.weight, style: currentSetting.style, decoration: currentSetting.decoration, size: size, box: true};
176
+ warn("Extra parameters in font definition.", str, position);
177
+ return { face: currentSetting.face, weight: currentSetting.weight, style: currentSetting.style, decoration: currentSetting.decoration, size: size};
178
+ }
179
+
180
+ // format 1: asterisk and number only
181
+ if (tokens[0].token === '*') {
182
+ tokens.shift();
183
+ if (tokens[0].type === 'number')
184
+ return processNumberOnly();
185
+ else {
186
+ warn("Expected font size number after *.", str, position);
187
+ }
188
+ }
189
+
190
+ // format 2: number only
191
+ if (tokens[0].type === 'number') {
192
+ return processNumberOnly();
193
+ }
194
+
195
+ // format 3: whole definition
196
+ var face = [];
197
+ var size;
198
+ var weight = "normal";
199
+ var style = "normal";
200
+ var decoration = "none";
201
+ var box = false;
202
+ var state = 'face';
203
+ var hyphenLast = false;
204
+ while (tokens.length) {
205
+ var currToken = tokens.shift();
206
+ var word = currToken.token.toLowerCase();
207
+ switch (state) {
208
+ case 'face':
209
+ if (hyphenLast || (word !== 'utf' && currToken.type !== 'number' && word !== "bold" && word !== "italic" && word !== "underline" && word !== "box")) {
210
+ if (face.length > 0 && currToken.token === '-') {
211
+ hyphenLast = true;
212
+ face[face.length-1] = face[face.length-1] + currToken.token;
213
+ }
214
+ else {
215
+ if (hyphenLast) {
216
+ hyphenLast = false;
217
+ face[face.length-1] = face[face.length-1] + currToken.token;
218
+ } else
219
+ face.push(currToken.token);
220
+ }
221
+ } else {
222
+ if (currToken.type === 'number') {
223
+ if (size) {
224
+ warn("Font size specified twice in font definition.", str, position);
225
+ } else {
226
+ size = currToken.token;
227
+ }
228
+ state = 'modifier';
229
+ } else if (word === "bold")
230
+ weight = "bold";
231
+ else if (word === "italic")
232
+ style = "italic";
233
+ else if (word === "underline")
234
+ decoration = "underline";
235
+ else if (word === "box") {
236
+ if (fontTypeCanHaveBox[cmd])
237
+ box = true;
238
+ else
239
+ warn("This font style doesn't support \"box\"", str, position);
240
+ state = "finished";
241
+ } else if (word === "utf") {
242
+ currToken = tokens.shift(); // this gets rid of the "8" after "utf"
243
+ state = "size";
244
+ } else
245
+ warn("Unknown parameter " + currToken.token + " in font definition.", str, position);
246
+ }
247
+ break;
248
+ case "size":
249
+ if (currToken.type === 'number') {
250
+ if (size) {
251
+ warn("Font size specified twice in font definition.", str, position);
252
+ } else {
253
+ size = currToken.token;
254
+ }
255
+ } else {
256
+ warn("Expected font size in font definition.", str, position);
257
+ }
258
+ state = 'modifier';
259
+ break;
260
+ case "modifier":
261
+ if (word === "bold")
262
+ weight = "bold";
263
+ else if (word === "italic")
264
+ style = "italic";
265
+ else if (word === "underline")
266
+ decoration = "underline";
267
+ else if (word === "box") {
268
+ if (fontTypeCanHaveBox[cmd])
269
+ box = true;
270
+ else
271
+ warn("This font style doesn't support \"box\"", str, position);
272
+ state = "finished";
273
+ } else
274
+ warn("Unknown parameter " + currToken.token + " in font definition.", str, position);
275
+ break;
276
+ case "finished":
277
+ warn("Extra characters found after \"box\" in font definition.", str, position);
278
+ break;
279
+ }
280
+ }
281
+
282
+ if (size === undefined) {
283
+ if (!currentSetting) {
284
+ warn("Must specify the size of the font since there is no default value.", str, position);
285
+ size = 12;
286
+ <<<<<<< HEAD
287
+ } else
288
+ size = currentSetting.size;
289
+ =======
290
+ }
291
+ size = currentSetting.size;
292
+ >>>>>>> origin/master
293
+ } else
294
+ size = parseFloat(size);
295
+
296
+ face = face.join(' ');
297
+ var psFont = fontTranslation(face);
298
+ var font = {};
299
+ if (psFont) {
300
+ font.face = psFont.face;
301
+ font.weight = psFont.weight;
302
+ font.style = psFont.style;
303
+ font.decoration = psFont.decoration;
304
+ font.size = size;
305
+ if (box)
306
+ font.box = true;
307
+ return font;
308
+ }
309
+ font.face = face;
310
+ font.weight = weight;
311
+ font.style = style;
312
+ font.decoration = decoration;
313
+ font.size = size;
314
+ if (box)
315
+ font.box = true;
316
+ return font;
317
+ };
318
+
319
+ var getChangingFont = function(cmd, tokens, str) {
320
+ if (tokens.length === 0)
321
+ return "Directive \"" + cmd + "\" requires a font as a parameter.";
322
+ multilineVars[cmd] = getFontParameter(tokens, multilineVars[cmd], str, 0, cmd);
323
+ return null;
324
+ };
325
+ var getGlobalFont = function(cmd, tokens, str) {
326
+ if (tokens.length === 0)
327
+ return "Directive \"" + cmd + "\" requires a font as a parameter.";
328
+ tune.formatting[cmd] = getFontParameter(tokens, tune.formatting[cmd], str, 0, cmd);
329
+ return null;
330
+ };
331
+
332
+ var setScale = function(cmd, tokens) {
333
+ var scratch = "";
334
+ window.ABCJS.parse.each(tokens, function(tok) {
335
+ scratch += tok.token;
336
+ });
337
+ var num = parseFloat(scratch);
338
+ if (isNaN(num) || num === 0)
339
+ return "Directive \"" + cmd + "\" requires a number as a parameter.";
340
+ tune.formatting.scale = num;
341
+
342
+ };
343
+
344
+ var getRequiredMeasurement = function(cmd, tokens) {
345
+ var points = tokenizer.getMeasurement(tokens);
346
+ if (points.used === 0 || tokens.length !== 0)
347
+ return { error: "Directive \"" + cmd + "\" requires a measurement as a parameter."};
348
+ return points.value;
349
+ };
350
+ var oneParameterMeasurement = function(cmd, tokens) {
351
+ var points = tokenizer.getMeasurement(tokens);
352
+ if (points.used === 0 || tokens.length !== 0)
353
+ return "Directive \"" + cmd + "\" requires a measurement as a parameter.";
354
+ tune.formatting[cmd] = points.value;
355
+ return null;
356
+ };
357
+
358
+ var addMultilineVar = function(key, cmd, tokens, min, max) {
359
+ if (tokens.length !== 1 || tokens[0].type !== 'number')
360
+ return "Directive \"" + cmd + "\" requires a number as a parameter.";
361
+ var i = tokens[0].intt;
362
+ if (min !== undefined && i < min)
363
+ return "Directive \"" + cmd + "\" requires a number greater than or equal to " + min + " as a parameter.";
364
+ if (max !== undefined && i > max)
365
+ return "Directive \"" + cmd + "\" requires a number less than or equal to " + max + " as a parameter.";
366
+ multilineVars[key] = i;
367
+ return null;
368
+ };
369
+
370
+ var addMultilineVarBool = function(key, cmd, tokens) {
371
+ var str = addMultilineVar(key, cmd, tokens, 0, 1);
372
+ if (str !== null) return str;
373
+ multilineVars[key] = (multilineVars[key] === 1);
374
+ return null;
375
+ <<<<<<< HEAD
376
+ };
377
+
378
+ var addMultilineVarOneParamChoice = function(key, cmd, tokens, choices) {
379
+ if (tokens.length !== 1)
380
+ return "Directive \"" + cmd + "\" requires one of [ " + choices.join(", ") + " ] as a parameter.";
381
+ var choice = tokens[0].token;
382
+ var found = false;
383
+ for (var i = 0; !found && i < choices.length; i++) {
384
+ if (choices[i] === choice)
385
+ found = true;
386
+ }
387
+ if (!found)
388
+ return "Directive \"" + cmd + "\" requires one of [ " + choices.join(", ") + " ] as a parameter.";
389
+ multilineVars[key] = choice;
390
+ return null;
391
+ =======
392
+ >>>>>>> origin/master
21
393
  };
22
394
 
23
395
  window.ABCJS.parse.parseDirective.parseFontChangeLine = function(textstr) {
@@ -44,77 +416,13 @@ window.ABCJS.parse.parseDirective = {};
44
416
  return textstr;
45
417
  };
46
418
 
419
+ var positionChoices = [ 'auto', 'above', 'below', 'hidden' ];
47
420
  window.ABCJS.parse.parseDirective.addDirective = function(str) {
48
- var getRequiredMeasurement = function(cmd, tokens) {
49
- var points = tokenizer.getMeasurement(tokens);
50
- if (points.used === 0 || tokens.length !== 0)
51
- return { error: "Directive \"" + cmd + "\" requires a measurement as a parameter."};
52
- return points.value;
53
- };
54
- var oneParameterMeasurement = function(cmd, tokens) {
55
- var points = tokenizer.getMeasurement(tokens);
56
- if (points.used === 0 || tokens.length !== 0)
57
- return "Directive \"" + cmd + "\" requires a measurement as a parameter.";
58
- tune.formatting[cmd] = points.value;
59
- return null;
60
- };
61
- var getFontParameter = function(tokens) {
62
- var font = {};
63
- var token = window.ABCJS.parse.last(tokens);
64
- if (token.type === 'number') {
65
- font.size = parseInt(token.token);
66
- tokens.pop();
67
- }
68
- if (tokens.length > 0) {
69
- var scratch = "";
70
- window.ABCJS.parse.each(tokens, function(tok) {
71
- if (tok.token !== '-') {
72
- if (scratch.length > 0) scratch += ' ';
73
- scratch += tok.token;
74
- }
75
- });
76
- font.font = scratch;
77
- }
78
- return font;
79
- };
80
- var getChangingFont = function(cmd, tokens) {
81
- if (tokens.length === 0)
82
- return "Directive \"" + cmd + "\" requires a font as a parameter.";
83
- multilineVars[cmd] = getFontParameter(tokens);
84
- return null;
85
- };
86
- var getGlobalFont = function(cmd, tokens) {
87
- if (tokens.length === 0)
88
- return "Directive \"" + cmd + "\" requires a font as a parameter.";
89
- tune.formatting[cmd] = getFontParameter(tokens);
90
- return null;
91
- };
92
-
93
- var addMultilineVar = function(key, cmd, tokens, min, max) {
94
- if (tokens.length !== 1 || tokens[0].type !== 'number')
95
- return "Directive \"" + cmd + "\" requires a number as a parameter.";
96
- var i = tokens[0].intt;
97
- if (min !== undefined && i < min)
98
- return "Directive \"" + cmd + "\" requires a number greater than or equal to " + min + " as a parameter.";
99
- if (max !== undefined && i > max)
100
- return "Directive \"" + cmd + "\" requires a number less than or equal to " + max + " as a parameter.";
101
- multilineVars[key] = i;
102
- return null;
103
- };
104
-
105
- var addMultilineVarBool = function(key, cmd, tokens) {
106
- var str = addMultilineVar(key, cmd, tokens, 0, 1);
107
- if (str !== null) return str;
108
- multilineVars[key] = (multilineVars[key] === 1);
109
- return null;
110
- };
111
-
112
421
  var tokens = tokenizer.tokenize(str, 0, str.length); // 3 or more % in a row, or just spaces after %% is just a comment
113
422
  if (tokens.length === 0 || tokens[0].type !== 'alpha') return null;
114
423
  var restOfString = str.substring(str.indexOf(tokens[0].token)+tokens[0].token.length);
115
424
  restOfString = tokenizer.stripComment(restOfString);
116
425
  var cmd = tokens.shift().token.toLowerCase();
117
- var num;
118
426
  var scratch = "";
119
427
  switch (cmd)
120
428
  {
@@ -122,47 +430,35 @@ window.ABCJS.parse.parseDirective = {};
122
430
  // Most of them are direct translations from the directives that will be parsed in. See abcm2ps's format.txt for info on each of these.
123
431
  // alignbars: { type: "number", optional: true },
124
432
  // aligncomposer: { type: "string", Enum: [ 'left', 'center','right' ], optional: true },
125
- // annotationfont: fontType,
126
433
  // bstemdown: { type: "boolean", optional: true },
127
434
  // continueall: { type: "boolean", optional: true },
128
435
  // dynalign: { type: "boolean", optional: true },
129
436
  // exprabove: { type: "boolean", optional: true },
130
437
  // exprbelow: { type: "boolean", optional: true },
131
438
  // flatbeams: { type: "boolean", optional: true },
132
- // footer: { type: "string", optional: true },
133
- // footerfont: fontType,
134
439
  // gchordbox: { type: "boolean", optional: true },
135
440
  // graceslurs: { type: "boolean", optional: true },
136
441
  // gracespacebefore: { type: "number", optional: true },
137
442
  // gracespaceinside: { type: "number", optional: true },
138
443
  // gracespaceafter: { type: "number", optional: true },
139
- // header: { type: "string", optional: true },
140
- // headerfont: fontType,
141
- // historyfont: fontType,
142
- // infofont: fontType,
143
444
  // infospace: { type: "number", optional: true },
144
445
  // lineskipfac: { type: "number", optional: true },
145
446
  // maxshrink: { type: "number", optional: true },
146
447
  // maxstaffsep: { type: "number", optional: true },
147
448
  // maxsysstaffsep: { type: "number", optional: true },
148
- // measurebox: { type: "boolean", optional: true },
149
- // measurefont: fontType,
150
449
  // notespacingfactor: { type: "number", optional: true },
151
450
  // parskipfac: { type: "number", optional: true },
152
- // partsbox: { type: "boolean", optional: true },
153
- // repeatfont: fontType,
154
- // rightmargin: { type: "number", optional: true },
155
451
  // slurheight: { type: "number", optional: true },
156
452
  // splittune: { type: "boolean", optional: true },
157
453
  // squarebreve: { type: "boolean", optional: true },
158
454
  // stemheight: { type: "number", optional: true },
159
455
  // straightflags: { type: "boolean", optional: true },
160
456
  // stretchstaff: { type: "boolean", optional: true },
161
- // textfont: fontType,
162
457
  // titleformat: { type: "string", optional: true },
458
+ <<<<<<< HEAD
459
+ =======
163
460
  // vocalabove: { type: "boolean", optional: true },
164
- // vocalfont: fontType,
165
- // wordsfont: fontType,
461
+ >>>>>>> origin/master
166
462
  case "bagpipes":tune.formatting.bagpipes = true;break;
167
463
  case "landscape":multilineVars.landscape = true;break;
168
464
  case "papersize":multilineVars.papersize = restOfString;break;
@@ -172,6 +468,12 @@ window.ABCJS.parse.parseDirective = {};
172
468
  case "titleleft":tune.formatting.titleleft = true;break;
173
469
  case "measurebox":tune.formatting.measurebox = true;break;
174
470
 
471
+ case "vocal": return addMultilineVarOneParamChoice("vocalPosition", cmd, tokens, positionChoices);
472
+ case "dynamic": return addMultilineVarOneParamChoice("dynamicPosition", cmd, tokens, positionChoices);
473
+ case "gchord": return addMultilineVarOneParamChoice("chordPosition", cmd, tokens, positionChoices);
474
+ case "ornament": return addMultilineVarOneParamChoice("ornamentPosition", cmd, tokens, positionChoices);
475
+ case "volume": return addMultilineVarOneParamChoice("volumePosition", cmd, tokens, positionChoices);
476
+
175
477
  case "botmargin":
176
478
  case "botspace":
177
479
  case "composerspace":
@@ -202,14 +504,7 @@ window.ABCJS.parse.parseDirective = {};
202
504
  tune.addSpacing(vskip);
203
505
  return null;
204
506
  case "scale":
205
- scratch = "";
206
- window.ABCJS.parse.each(tokens, function(tok) {
207
- scratch += tok.token;
208
- });
209
- num = parseFloat(scratch);
210
- if (isNaN(num) || num === 0)
211
- return "Directive \"" + cmd + "\" requires a number as a parameter.";
212
- tune.formatting.scale = num;
507
+ setScale(cmd, tokens);
213
508
  break;
214
509
  case "sep":
215
510
  if (tokens.length === 0)
@@ -244,6 +539,10 @@ window.ABCJS.parse.parseDirective = {};
244
539
  scratch = addMultilineVarBool('printTempo', cmd, tokens);
245
540
  if (scratch !== null) return scratch;
246
541
  break;
542
+ case "partsbox":
543
+ scratch = addMultilineVarBool('partsBox', cmd, tokens);
544
+ if (scratch !== null) return scratch;
545
+ break;
247
546
  case "measurenb":
248
547
  case "barnumbers":
249
548
  scratch = addMultilineVar('barNumbers', cmd, tokens);
@@ -277,43 +576,54 @@ window.ABCJS.parse.parseDirective = {};
277
576
  break;
278
577
  case "setfont":
279
578
  var sfTokens = tokenizer.tokenize(restOfString, 0, restOfString.length);
280
- var sfDone = false;
579
+ // var sfDone = false;
281
580
  if (sfTokens.length >= 4) {
282
581
  if (sfTokens[0].token === '-' && sfTokens[1].type === 'number') {
283
582
  var sfNum = parseInt(sfTokens[1].token);
284
583
  if (sfNum >= 1 && sfNum <= 4) {
285
584
  if (!multilineVars.setfont)
286
585
  multilineVars.setfont = [];
287
- var sfSize = sfTokens.pop();
288
- if (sfSize.type === 'number') {
289
- sfSize = parseInt(sfSize.token);
290
- var sfFontName = '';
291
- for (var sfi = 2; sfi < sfTokens.length; sfi++)
292
- sfFontName += sfTokens[sfi].token;
293
- multilineVars.setfont[sfNum] = { font: sfFontName, size: sfSize };
294
- sfDone = true;
295
- }
586
+ sfTokens.shift();
587
+ sfTokens.shift();
588
+ multilineVars.setfont[sfNum] = getFontParameter(sfTokens, multilineVars.setfont[sfNum], str, 0, 'setfont');
589
+ // var sfSize = sfTokens.pop();
590
+ // if (sfSize.type === 'number') {
591
+ // sfSize = parseInt(sfSize.token);
592
+ // var sfFontName = '';
593
+ // for (var sfi = 2; sfi < sfTokens.length; sfi++)
594
+ // sfFontName += sfTokens[sfi].token;
595
+ // multilineVars.setfont[sfNum] = { face: sfFontName, size: sfSize };
596
+ // sfDone = true;
597
+ // }
296
598
  }
297
599
  }
298
600
  }
299
- if (!sfDone)
300
- return "Bad parameters: " + cmd;
601
+ // if (!sfDone)
602
+ // return "Bad parameters: " + cmd;
301
603
  break;
302
604
  case "gchordfont":
303
605
  case "partsfont":
304
606
  case "vocalfont":
305
607
  case "textfont":
306
- return getChangingFont(cmd, tokens);
307
- case "barlabelfont":
308
- case "barnumberfont":
608
+ case "annotationfont":
609
+ case "historyfont":
610
+ case "infofont":
611
+ case "measurefont":
612
+ case "repeatfont":
613
+ case "wordsfont":
614
+ return getChangingFont(cmd, tokens, str);
309
615
  case "composerfont":
310
616
  case "subtitlefont":
311
617
  case "tempofont":
312
618
  case "titlefont":
313
619
  case "voicefont":
314
- return getGlobalFont(cmd, tokens);
620
+ case "footerfont":
621
+ case "headerfont":
622
+ return getGlobalFont(cmd, tokens, str);
623
+ case "barlabelfont":
624
+ case "barnumberfont":
315
625
  case "barnumfont":
316
- return getGlobalFont("barnumberfont", tokens);
626
+ return getChangingFont("measurefont", tokens, str);
317
627
  case "staves":
318
628
  case "score":
319
629
  multilineVars.score_is_present = true;
@@ -411,19 +721,27 @@ window.ABCJS.parse.parseDirective = {};
411
721
  tune.addNewPage(pgNum.digits === 0 ? -1 : pgNum.value);
412
722
  break;
413
723
 
414
- case "abc-copyright":
415
- case "abc-creator":
416
- case "abc-version":
417
- case "abc-charset":
418
- case "abc-edited-by":
419
- tune.addMetaText(cmd, restOfString);
724
+ case "abc":
725
+ var arr = restOfString.split(' ');
726
+ switch (arr[0]) {
727
+ case "-copyright":
728
+ case "-creator":
729
+ case "-edited-by":
730
+ case "-version":
731
+ case "-charset":
732
+ var subCmd = arr.shift();
733
+ tune.addMetaText(cmd+subCmd, arr.join(' '));
734
+ break;
735
+ default:
736
+ return "Unknown directive: " + cmd+arr[0];
737
+ }
420
738
  break;
421
739
  case "header":
422
740
  case "footer":
423
741
  var footerStr = tokenizer.getMeat(restOfString, 0, restOfString.length);
424
742
  footerStr = restOfString.substring(footerStr.start, footerStr.end);
425
743
  if (footerStr.charAt(0) === '"' && footerStr.charAt(footerStr.length-1) === '"' )
426
- footerStr = footerStr.substring(1, footerStr.length-2);
744
+ footerStr = footerStr.substring(1, footerStr.length-1);
427
745
  var footerArr = footerStr.split('\t');
428
746
  var footer = {};
429
747
  if (footerArr.length === 1)
@@ -432,8 +750,8 @@ window.ABCJS.parse.parseDirective = {};
432
750
  footer = { left: footerArr[0], center: footerArr[1], right: "" };
433
751
  else
434
752
  footer = { left: footerArr[0], center: footerArr[1], right: footerArr[2] };
435
- if (footerArr.length > 3)
436
- warn("Too many tabs in "+cmd+": "+footerArr.length+" found.", restOfString, 0);
753
+ if (footerArr.length > 3)
754
+ warn("Too many tabs in " + cmd + ": " + footerArr.length + " found.", restOfString, 0);
437
755
 
438
756
  tune.addMetaTextObj(cmd, footer);
439
757
  break;
@@ -542,5 +860,28 @@ window.ABCJS.parse.parseDirective = {};
542
860
  }
543
861
  return null;
544
862
  };
545
-
863
+ window.ABCJS.parse.parseDirective.globalFormatting = function(formatHash) {
864
+ for (var cmd in formatHash) {
865
+ if (formatHash.hasOwnProperty(cmd)) {
866
+ var value = ''+formatHash[cmd];
867
+ var tokens = tokenizer.tokenize(value, 0, value.length);
868
+ var scratch;
869
+ switch (cmd) {
870
+ case "titlefont":
871
+ case "gchordfont":
872
+ getChangingFont(cmd, tokens, value);
873
+ break;
874
+ case "scale":
875
+ setScale(cmd, tokens);
876
+ break;
877
+ case "partsbox":
878
+ scratch = addMultilineVarBool('partsBox', cmd, tokens);
879
+ if (scratch !== null) warn(scratch);
880
+ break;
881
+ default:
882
+ warn("Formatting directive unrecognized: ", cmd, 0);
883
+ }
884
+ }
885
+ }
886
+ };
546
887
  })();