abcjs-rails 1.11 → 2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (31) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/javascripts/abcjs/api/abc_animation.js +41 -1
  3. data/app/assets/javascripts/abcjs/api/abc_tunebook.js +5 -0
  4. data/app/assets/javascripts/abcjs/data/abc_tune.js +4 -3
  5. data/app/assets/javascripts/abcjs/edit/abc_editor.js +10 -0
  6. data/app/assets/javascripts/abcjs/parse/abc_parse.js +120 -19
  7. data/app/assets/javascripts/abcjs/parse/abc_parse_directive.js +456 -115
  8. data/app/assets/javascripts/abcjs/raphael.js +2 -2
  9. data/app/assets/javascripts/abcjs/write/abc_absolute_element.js +111 -4
  10. data/app/assets/javascripts/abcjs/write/abc_abstract_engraver.js +899 -0
  11. data/app/assets/javascripts/abcjs/write/abc_beam_element.js +263 -37
  12. data/app/assets/javascripts/abcjs/write/abc_create_clef.js +76 -0
  13. data/app/assets/javascripts/abcjs/write/abc_create_key_signature.js +41 -0
  14. data/app/assets/javascripts/abcjs/write/abc_create_time_signature.js +51 -0
  15. data/app/assets/javascripts/abcjs/write/{abc_cresendo_element.js → abc_crescendo_element.js} +32 -1
  16. data/app/assets/javascripts/abcjs/write/abc_decoration.js +321 -0
  17. data/app/assets/javascripts/abcjs/write/abc_dynamic_decoration.js +22 -1
  18. data/app/assets/javascripts/abcjs/write/abc_ending_element.js +31 -1
  19. data/app/assets/javascripts/abcjs/write/abc_engraver_controller.js +359 -0
  20. data/app/assets/javascripts/abcjs/write/abc_glyphs.js +119 -9
  21. data/app/assets/javascripts/abcjs/write/abc_layout.js +2 -2
  22. data/app/assets/javascripts/abcjs/write/abc_relative_element.js +106 -8
  23. data/app/assets/javascripts/abcjs/write/abc_renderer.js +754 -0
  24. data/app/assets/javascripts/abcjs/write/abc_staff_group_element.js +249 -9
  25. data/app/assets/javascripts/abcjs/write/abc_tempo_element.js +104 -0
  26. data/app/assets/javascripts/abcjs/write/abc_tie_element.js +69 -22
  27. data/app/assets/javascripts/abcjs/write/abc_triplet_element.js +77 -10
  28. data/app/assets/javascripts/abcjs/write/abc_voice_element.js +100 -8
  29. data/app/assets/javascripts/abcjs/write/abc_write.js +64 -68
  30. data/lib/abcjs-rails/version.rb +1 -1
  31. metadata +12 -4
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
  })();