abcjs-rails 2.3 → 3.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.
- checksums.yaml +4 -4
- data/app/assets/javascripts/abcjs/api/abc_animation.js +166 -4
- data/app/assets/javascripts/abcjs/api/abc_tunebook.js +170 -15
- data/app/assets/javascripts/abcjs/data/abc_tune.js +69 -47
- data/app/assets/javascripts/abcjs/edit/abc_editor.js +78 -37
- data/app/assets/javascripts/abcjs/midi/abc_midi_controls.js +513 -0
- data/app/assets/javascripts/abcjs/midi/abc_midi_create.js +29 -7
- data/app/assets/javascripts/abcjs/midi/abc_midi_flattener.js +21 -18
- data/app/assets/javascripts/abcjs/midi/abc_midi_js_preparer.js +233 -0
- data/app/assets/javascripts/abcjs/midi/abc_midi_renderer.js +3 -229
- data/app/assets/javascripts/abcjs/midi/abc_midi_sequencer.js +11 -3
- data/app/assets/javascripts/abcjs/parse/abc_common.js +24 -0
- data/app/assets/javascripts/abcjs/parse/abc_parse.js +58 -16
- data/app/assets/javascripts/abcjs/parse/abc_parse_header.js +4 -1
- data/app/assets/javascripts/abcjs/parse/abc_parse_key_voice.js +5 -0
- data/app/assets/javascripts/abcjs/write/abc_absolute_element.js +9 -2
- data/app/assets/javascripts/abcjs/write/abc_abstract_engraver.js +71 -19
- data/app/assets/javascripts/abcjs/write/abc_beam_element.js +11 -3
- data/app/assets/javascripts/abcjs/write/abc_brace_element.js +51 -0
- data/app/assets/javascripts/abcjs/write/abc_create_clef.js +3 -3
- data/app/assets/javascripts/abcjs/write/abc_create_key_signature.js +3 -3
- data/app/assets/javascripts/abcjs/write/abc_create_time_signature.js +3 -3
- data/app/assets/javascripts/abcjs/write/abc_crescendo_element.js +4 -1
- data/app/assets/javascripts/abcjs/write/abc_decoration.js +1 -1
- data/app/assets/javascripts/abcjs/write/abc_engraver_controller.js +10 -9
- data/app/assets/javascripts/abcjs/write/abc_glyphs.js +1 -1
- data/app/assets/javascripts/abcjs/write/abc_relative_element.js +1 -1
- data/app/assets/javascripts/abcjs/write/abc_renderer.js +85 -13
- data/app/assets/javascripts/abcjs/write/abc_staff_group_element.js +16 -0
- data/app/assets/javascripts/abcjs/write/abc_tempo_element.js +31 -11
- data/app/assets/javascripts/abcjs/write/abc_tie_element.js +8 -1
- data/lib/abcjs-rails/version.rb +1 -1
- metadata +6 -3
@@ -1,5 +1,5 @@
|
|
1
1
|
// abc_midi_sequencer.js: Turn parsed abc into a linear series of events.
|
2
|
-
// Copyright (C) 2010,
|
2
|
+
// Copyright (C) 2010,2016 Gregory Dyke (gregdyke at gmail dot com) and Paul Rosen
|
3
3
|
//
|
4
4
|
// This program is free software: you can redistribute it and/or modify
|
5
5
|
// it under the terms of the GNU General Public License as published by
|
@@ -31,9 +31,14 @@ if (!window.ABCJS.midi)
|
|
31
31
|
// Global options
|
32
32
|
options = options || {};
|
33
33
|
var qpm = options.qpm || 180; // The tempo if there isn't a tempo specified.
|
34
|
-
var program = options.program ||
|
34
|
+
var program = options.program || 0; // The program if there isn't a program specified.
|
35
35
|
var transpose = options.transpose || 0;
|
36
36
|
var channel = options.channel || 0;
|
37
|
+
// All of the above overrides need to be integers
|
38
|
+
qpm = parseInt(qpm, 10);
|
39
|
+
program = parseInt(program, 10);
|
40
|
+
transpose = parseInt(transpose, 10);
|
41
|
+
channel = parseInt(channel, 10);
|
37
42
|
|
38
43
|
var bagpipes = abctune.formatting.bagpipes; // If it is bagpipes, then the gracenotes are played on top of the main note.
|
39
44
|
if (bagpipes)
|
@@ -142,7 +147,7 @@ if (!window.ABCJS.midi)
|
|
142
147
|
// figure out repeats and endings --
|
143
148
|
// The important part is where there is a start repeat, and end repeat, or a first ending.
|
144
149
|
var endRepeat = (elem.type === "bar_right_repeat" || elem.type === "bar_dbl_repeat");
|
145
|
-
var startEnding = (elem.startEnding
|
150
|
+
var startEnding = (elem.startEnding === '1');
|
146
151
|
var startRepeat = (elem.type === "bar_left_repeat" || elem.type === "bar_dbl_repeat" || elem.type === "bar_thick_thin" || elem.type === "bar_thin_thick" || elem.type === "bar_thin_thin" || elem.type === "bar_right_repeat");
|
147
152
|
if (endRepeat) {
|
148
153
|
var s = startRepeatPlaceholder[voiceNumber];
|
@@ -150,6 +155,9 @@ if (!window.ABCJS.midi)
|
|
150
155
|
var e = skipEndingPlaceholder[voiceNumber];
|
151
156
|
if (!e) e = voices[voiceNumber].length; // If there wasn't a first ending marker, then we copy everything.
|
152
157
|
voices[voiceNumber] = voices[voiceNumber].concat(voices[voiceNumber].slice(s, e));
|
158
|
+
// reset these in case there is a second repeat later on.
|
159
|
+
skipEndingPlaceholder[voiceNumber] = undefined;
|
160
|
+
startRepeatPlaceholder[voiceNumber] = undefined;
|
153
161
|
}
|
154
162
|
if (startEnding)
|
155
163
|
skipEndingPlaceholder[voiceNumber] = voices[voiceNumber].length;
|
@@ -30,6 +30,30 @@ window.ABCJS.parse.clone = function(source) {
|
|
30
30
|
return destination;
|
31
31
|
};
|
32
32
|
|
33
|
+
window.ABCJS.parse.cloneArray = function(source) {
|
34
|
+
var destination = [];
|
35
|
+
for (var i = 0; i < source.length; i++) {
|
36
|
+
destination.push(ABCJS.parse.clone(source[i]));
|
37
|
+
}
|
38
|
+
return destination;
|
39
|
+
};
|
40
|
+
|
41
|
+
window.ABCJS.parse.cloneHashOfHash = function(source) {
|
42
|
+
var destination = {};
|
43
|
+
for (var property in source)
|
44
|
+
if (source.hasOwnProperty(property))
|
45
|
+
destination[property] = ABCJS.parse.clone(source[property]);
|
46
|
+
return destination;
|
47
|
+
};
|
48
|
+
|
49
|
+
window.ABCJS.parse.cloneHashOfArrayOfHash = function(source) {
|
50
|
+
var destination = {};
|
51
|
+
for (var property in source)
|
52
|
+
if (source.hasOwnProperty(property))
|
53
|
+
destination[property] = ABCJS.parse.cloneArray(source[property]);
|
54
|
+
return destination;
|
55
|
+
};
|
56
|
+
|
33
57
|
window.ABCJS.parse.gsub = function(source, pattern, replacement) {
|
34
58
|
return source.split(pattern).join(replacement);
|
35
59
|
};
|
@@ -840,14 +840,12 @@ window.ABCJS.parse.Parse = function() {
|
|
840
840
|
if (multilineVars.currentVoice.style)
|
841
841
|
params.style = multilineVars.currentVoice.style;
|
842
842
|
}
|
843
|
+
var isFirstVoice = multilineVars.currentVoice === undefined || (multilineVars.currentVoice.staffNum === 0 && multilineVars.currentVoice.index === 0);
|
844
|
+
if (multilineVars.barNumbers === 0 && isFirstVoice && multilineVars.currBarNumber !== 1)
|
845
|
+
params.barNumber = multilineVars.currBarNumber;
|
843
846
|
tune.startNewLine(params);
|
844
847
|
|
845
848
|
multilineVars.partForNextLine = "";
|
846
|
-
if (multilineVars.currentVoice === undefined || (multilineVars.currentVoice.staffNum === multilineVars.staves.length-1 && multilineVars.staves[multilineVars.currentVoice.staffNum].numVoices-1 === multilineVars.currentVoice.index)) {
|
847
|
-
//multilineVars.meter = null;
|
848
|
-
if (multilineVars.barNumbers === 0)
|
849
|
-
multilineVars.barNumOnNextNote = multilineVars.currBarNumber;
|
850
|
-
}
|
851
849
|
}
|
852
850
|
|
853
851
|
var letter_to_grace = function(line, i) {
|
@@ -1145,9 +1143,12 @@ window.ABCJS.parse.Parse = function() {
|
|
1145
1143
|
else if (bar.endEnding)
|
1146
1144
|
multilineVars.barFirstEndingNum = undefined;
|
1147
1145
|
if (bar.type !== 'bar_invisible' && multilineVars.measureNotEmpty) {
|
1148
|
-
multilineVars.
|
1149
|
-
if (
|
1150
|
-
multilineVars.
|
1146
|
+
var isFirstVoice = multilineVars.currentVoice === undefined || (multilineVars.currentVoice.staffNum === 0 && multilineVars.currentVoice.index === 0);
|
1147
|
+
if (isFirstVoice) {
|
1148
|
+
multilineVars.currBarNumber++;
|
1149
|
+
if (multilineVars.barNumbers && multilineVars.currBarNumber % multilineVars.barNumbers === 0)
|
1150
|
+
bar.barNumber = multilineVars.currBarNumber;
|
1151
|
+
}
|
1151
1152
|
}
|
1152
1153
|
multilineVars.addFormattingOptions(el, tune.formatting, 'bar');
|
1153
1154
|
tune.appendElement('bar', startOfLine+i, startOfLine+i+ret[0], bar);
|
@@ -1291,10 +1292,7 @@ window.ABCJS.parse.Parse = function() {
|
|
1291
1292
|
if (chordDuration !== null) {
|
1292
1293
|
el.duration = el.duration * chordDuration;
|
1293
1294
|
}
|
1294
|
-
|
1295
|
-
el.barNumber = multilineVars.barNumOnNextNote;
|
1296
|
-
multilineVars.barNumOnNextNote = null;
|
1297
|
-
}
|
1295
|
+
|
1298
1296
|
multilineVars.addFormattingOptions(el, tune.formatting, 'note');
|
1299
1297
|
tune.appendElement('note', startOfLine+chordStartChar, startOfLine+i, el);
|
1300
1298
|
multilineVars.measureNotEmpty = true;
|
@@ -1365,10 +1363,6 @@ window.ABCJS.parse.Parse = function() {
|
|
1365
1363
|
el.duration = durationOfMeasure(multilineVars);
|
1366
1364
|
}
|
1367
1365
|
|
1368
|
-
if (multilineVars.barNumOnNextNote) {
|
1369
|
-
el.barNumber = multilineVars.barNumOnNextNote;
|
1370
|
-
multilineVars.barNumOnNextNote = null;
|
1371
|
-
}
|
1372
1366
|
multilineVars.addFormattingOptions(el, tune.formatting, 'note');
|
1373
1367
|
tune.appendElement('note', startOfLine+startI, startOfLine+i, el);
|
1374
1368
|
multilineVars.measureNotEmpty = true;
|
@@ -1400,12 +1394,57 @@ window.ABCJS.parse.Parse = function() {
|
|
1400
1394
|
parseLine(ret.str);
|
1401
1395
|
};
|
1402
1396
|
|
1397
|
+
function appendLastMeasure(voice, nextVoice) {
|
1398
|
+
voice.push({
|
1399
|
+
el_type: 'hint'
|
1400
|
+
});
|
1401
|
+
for (var i = 0; i < nextVoice.length; i++) {
|
1402
|
+
var element = nextVoice[i];
|
1403
|
+
var hint = window.ABCJS.parse.clone(element);
|
1404
|
+
voice.push(hint);
|
1405
|
+
if (element.el_type === 'bar')
|
1406
|
+
return;
|
1407
|
+
}
|
1408
|
+
}
|
1409
|
+
|
1410
|
+
function addHintMeasure(staff, nextStaff) {
|
1411
|
+
for (var i = 0; i < staff.length; i++) {
|
1412
|
+
var stave = staff[i];
|
1413
|
+
var nextStave = nextStaff[i];
|
1414
|
+
if (nextStave) { // Be sure there is the same number of staves on the next line.
|
1415
|
+
for (var j = 0; j < nextStave.voices.length; j++) {
|
1416
|
+
var nextVoice = nextStave.voices[j];
|
1417
|
+
var voice = stave.voices[j];
|
1418
|
+
if (voice) { // Be sure there are the same number of voices on the previous line.
|
1419
|
+
appendLastMeasure(voice, nextVoice);
|
1420
|
+
}
|
1421
|
+
}
|
1422
|
+
}
|
1423
|
+
}
|
1424
|
+
}
|
1425
|
+
|
1426
|
+
function addHintMeasures() {
|
1427
|
+
for (var i = 0; i < tune.lines.length; i++) {
|
1428
|
+
var line = tune.lines[i].staff;
|
1429
|
+
if (line) {
|
1430
|
+
var j = i+1;
|
1431
|
+
while (j < tune.lines.length && tune.lines[j].staff === undefined)
|
1432
|
+
j++;
|
1433
|
+
if (j < tune.lines.length) {
|
1434
|
+
var nextLine = tune.lines[j].staff;
|
1435
|
+
addHintMeasure(line, nextLine);
|
1436
|
+
}
|
1437
|
+
}
|
1438
|
+
}
|
1439
|
+
}
|
1440
|
+
|
1403
1441
|
this.parse = function(strTune, switches) {
|
1404
1442
|
// the switches are optional and cause a difference in the way the tune is parsed.
|
1405
1443
|
// switches.header_only : stop parsing when the header is finished
|
1406
1444
|
// switches.stop_on_warning : stop at the first warning encountered.
|
1407
1445
|
// switches.print: format for the page instead of the browser.
|
1408
1446
|
// switches.format: a hash of the desired formatting commands.
|
1447
|
+
// switches.hint_measures: put the next measure at the end of the current line.
|
1409
1448
|
if (!switches) switches = {};
|
1410
1449
|
tune.reset();
|
1411
1450
|
if (switches.print)
|
@@ -1482,5 +1521,8 @@ window.ABCJS.parse.Parse = function() {
|
|
1482
1521
|
if (err !== "normal_abort")
|
1483
1522
|
throw err;
|
1484
1523
|
}
|
1524
|
+
if (switches.hint_measures) {
|
1525
|
+
addHintMeasures();
|
1526
|
+
}
|
1485
1527
|
};
|
1486
1528
|
};
|
@@ -34,7 +34,10 @@ window.ABCJS.parse.ParseHeader = function(tokenizer, warn, multilineVars, tune)
|
|
34
34
|
tune.addSubtitle(tokenizer.translateString(tokenizer.stripComment(title))); // display secondary title
|
35
35
|
else
|
36
36
|
{
|
37
|
-
|
37
|
+
var titleStr = tokenizer.translateString(tokenizer.theReverser(tokenizer.stripComment(title)));
|
38
|
+
if (multilineVars.titlecaps)
|
39
|
+
titleStr = titleStr.toUpperCase();
|
40
|
+
tune.addMetaText("title", titleStr);
|
38
41
|
multilineVars.hasMainTitle = true;
|
39
42
|
}
|
40
43
|
};
|
@@ -403,6 +403,11 @@ window.ABCJS.parse.parseKeyVoice = {};
|
|
403
403
|
mode = retMode.token;
|
404
404
|
}
|
405
405
|
}
|
406
|
+
// Be sure that the key specified is in the list: not all keys are physically possible, like Cbmin.
|
407
|
+
if (window.ABCJS.parse.parseKeyVoice.standardKey(key) === undefined) {
|
408
|
+
warn("Unsupported key signature: " + key, str, 0);
|
409
|
+
return ret;
|
410
|
+
}
|
406
411
|
}
|
407
412
|
// We need to do a deep copy because we are going to modify it
|
408
413
|
var oldKey = window.ABCJS.parse.parseKeyVoice.deepCopyKey(multilineVars.key);
|
@@ -25,8 +25,9 @@ if (!window.ABCJS.write)
|
|
25
25
|
// duration - actual musical duration - different from notehead duration in triplets. refer to abcelem to get the notehead duration
|
26
26
|
// minspacing - spacing which must be taken on top of the width defined by the duration
|
27
27
|
// type is a meta-type for the element. It is not necessary for drawing, but it is useful to make semantic sense of the element. For instance, it can be used in the element's class name.
|
28
|
-
ABCJS.write.AbsoluteElement = function(abcelem, duration, minspacing, type) {
|
28
|
+
ABCJS.write.AbsoluteElement = function(abcelem, duration, minspacing, type, tuneNumber) {
|
29
29
|
//console.log("Absolute:",abcelem, type);
|
30
|
+
this.tuneNumber = tuneNumber;
|
30
31
|
this.abcelem = abcelem;
|
31
32
|
this.duration = duration;
|
32
33
|
this.minspacing = minspacing || 0;
|
@@ -165,6 +166,10 @@ ABCJS.write.AbsoluteElement.prototype.setX = function (x) {
|
|
165
166
|
this.children[i].setX(x);
|
166
167
|
};
|
167
168
|
|
169
|
+
ABCJS.write.AbsoluteElement.prototype.setHint = function () {
|
170
|
+
this.hint = true;
|
171
|
+
};
|
172
|
+
|
168
173
|
ABCJS.write.AbsoluteElement.prototype.draw = function (renderer, bartop) {
|
169
174
|
this.elemset = renderer.paper.set();
|
170
175
|
if (this.invisible) return;
|
@@ -179,13 +184,15 @@ ABCJS.write.AbsoluteElement.prototype.draw = function (renderer, bartop) {
|
|
179
184
|
this.elemset.push(renderer.endGroup(this.type));
|
180
185
|
if (this.klass)
|
181
186
|
this.setClass("mark", "", "#00ff00");
|
187
|
+
if (this.hint)
|
188
|
+
this.setClass("abcjs-hint", "", null);
|
182
189
|
var color = ABCJS.write.debugPlacement ? "rgba(0,0,0,0.3)" : "rgba(0,0,0,0)"; // Create transparent box that encompasses the element, and not so transparent to debug it.
|
183
190
|
var target = renderer.printShadedBox(this.x, renderer.calcY(this.top), this.w, renderer.calcY(this.bottom)-renderer.calcY(this.top), color);
|
184
191
|
var self = this;
|
185
192
|
var controller = renderer.controller;
|
186
193
|
// this.elemset.mouseup(function () {
|
187
194
|
target.mouseup(function () {
|
188
|
-
controller.notifySelect(self);
|
195
|
+
controller.notifySelect(self, self.tuneNumber);
|
189
196
|
});
|
190
197
|
this.abcelem.abselem = this;
|
191
198
|
|
@@ -43,9 +43,10 @@ ABCJS.write.getDurlog = function(duration) {
|
|
43
43
|
return Math.floor(Math.log(duration)/Math.log(2));
|
44
44
|
};
|
45
45
|
|
46
|
-
ABCJS.write.AbstractEngraver = function(bagpipes, renderer) {
|
46
|
+
ABCJS.write.AbstractEngraver = function(bagpipes, renderer, tuneNumber) {
|
47
47
|
this.decoration = new ABCJS.write.Decoration();
|
48
48
|
this.renderer = renderer;
|
49
|
+
this.tuneNumber = tuneNumber;
|
49
50
|
this.isBagpipes = bagpipes;
|
50
51
|
this.chartable = {rest:{0:"rests.whole", 1:"rests.half", 2:"rests.quarter", 3:"rests.8th", 4: "rests.16th",5: "rests.32nd", 6: "rests.64th", 7: "rests.128th"},
|
51
52
|
note:{"-1": "noteheads.dbl", 0:"noteheads.whole", 1:"noteheads.half", 2:"noteheads.quarter", 3:"noteheads.quarter", 4:"noteheads.quarter", 5:"noteheads.quarter", 6:"noteheads.quarter", 7:"noteheads.quarter", 'nostem':"noteheads.quarter"},
|
@@ -138,9 +139,11 @@ ABCJS.write.AbstractEngraver.prototype.createABCLine = function(staffs, tempo) {
|
|
138
139
|
this.staffgroup = new ABCJS.write.StaffGroupElement();
|
139
140
|
this.tempoSet = false;
|
140
141
|
for (this.s = 0; this.s < staffs.length; this.s++) {
|
142
|
+
if (ABCJS.write.hint)
|
143
|
+
this.restoreState();
|
144
|
+
ABCJS.write.hint = false;
|
141
145
|
this.createABCStaff(staffs[this.s], tempo);
|
142
146
|
}
|
143
|
-
|
144
147
|
return this.staffgroup;
|
145
148
|
};
|
146
149
|
|
@@ -155,16 +158,20 @@ ABCJS.write.AbstractEngraver.prototype.createABCStaff = function(abcstaff, tempo
|
|
155
158
|
this.voice.duplicate = true; // bar lines and other duplicate info need not be created
|
156
159
|
}
|
157
160
|
if (abcstaff.title && abcstaff.title[this.v]) this.voice.header=abcstaff.title[this.v];
|
158
|
-
var clef = ABCJS.write.createClef(abcstaff.clef);
|
159
|
-
if (clef)
|
160
|
-
|
161
|
-
|
161
|
+
var clef = ABCJS.write.createClef(abcstaff.clef, this.tuneNumber);
|
162
|
+
if (clef) {
|
163
|
+
if (this.v ===0 && abcstaff.barNumber) {
|
164
|
+
this.addMeasureNumber(abcstaff.barNumber, clef);
|
165
|
+
}
|
166
|
+
this.voice.addChild(clef);
|
167
|
+
}
|
168
|
+
var keySig = ABCJS.write.createKeySignature(abcstaff.key, this.tuneNumber);
|
162
169
|
if (keySig) {
|
163
170
|
this.voice.addChild(keySig);
|
164
171
|
this.startlimitelem = keySig; // limit ties here
|
165
172
|
}
|
166
173
|
if (abcstaff.meter) {
|
167
|
-
var ts = ABCJS.write.createTimeSignature(abcstaff.meter);
|
174
|
+
var ts = ABCJS.write.createTimeSignature(abcstaff.meter, this.tuneNumber);
|
168
175
|
this.voice.addChild(ts);
|
169
176
|
this.startlimitelem = ts; // limit ties here
|
170
177
|
}
|
@@ -174,6 +181,18 @@ ABCJS.write.AbstractEngraver.prototype.createABCStaff = function(abcstaff, tempo
|
|
174
181
|
this.staffgroup.addVoice(this.voice,this.s,staffLines);
|
175
182
|
this.createABCVoice(abcstaff.voices[this.v],tempo);
|
176
183
|
this.staffgroup.setStaffLimits(this.voice);
|
184
|
+
//Tony: Here I am following what staves need to be surrounded by the brace, by incrementing the length of the brace class.
|
185
|
+
//So basically this keeps incrementing the number of staff surrounded by the brace until it sees "end".
|
186
|
+
//This then gets processed in abc_staff_group_element.js, so that it will have the correct top and bottom coordinates for the brace.
|
187
|
+
if(abcstaff.brace === "start"){
|
188
|
+
this.staffgroup.brace = new ABCJS.write.BraceElem(1, true);
|
189
|
+
}
|
190
|
+
else if(abcstaff.brace === "end" && this.staffgroup.brace) {
|
191
|
+
this.staffgroup.brace.increaseStavesIncluded();
|
192
|
+
}
|
193
|
+
else if(abcstaff.brace === "continue" && this.staffgroup.brace){
|
194
|
+
this.staffgroup.brace.increaseStavesIncluded();
|
195
|
+
}
|
177
196
|
}
|
178
197
|
};
|
179
198
|
|
@@ -188,11 +207,13 @@ ABCJS.write.AbstractEngraver.prototype.createABCVoice = function(abcline, tempo)
|
|
188
207
|
for (var slur in this.slurs) {
|
189
208
|
if (this.slurs.hasOwnProperty(slur)) {
|
190
209
|
this.slurs[slur]= new ABCJS.write.TieElem(null, null, this.slurs[slur].above, this.slurs[slur].force, false);
|
210
|
+
if (ABCJS.write.hint) this.slurs[slur].setHint();
|
191
211
|
this.voice.addOther(this.slurs[slur]);
|
192
212
|
}
|
193
213
|
}
|
194
214
|
for (var i=0; i<this.ties.length; i++) {
|
195
215
|
this.ties[i]=new ABCJS.write.TieElem(null, null, this.ties[i].above, this.ties[i].force, true);
|
216
|
+
if (ABCJS.write.hint) this.ties[i].setHint();
|
196
217
|
this.voice.addOther(this.ties[i]);
|
197
218
|
}
|
198
219
|
|
@@ -202,7 +223,7 @@ ABCJS.write.AbstractEngraver.prototype.createABCVoice = function(abcline, tempo)
|
|
202
223
|
for (i=0; i<abselems.length; i++) {
|
203
224
|
if (!this.tempoSet && tempo && !tempo.suppress) {
|
204
225
|
this.tempoSet = true;
|
205
|
-
abselems[i].addChild(new ABCJS.write.TempoElement(tempo));
|
226
|
+
abselems[i].addChild(new ABCJS.write.TempoElement(tempo, this.tuneNumber));
|
206
227
|
}
|
207
228
|
this.voice.addChild(abselems[i]);
|
208
229
|
}
|
@@ -211,6 +232,19 @@ ABCJS.write.AbstractEngraver.prototype.createABCVoice = function(abcline, tempo)
|
|
211
232
|
this.pushCrossLineElems();
|
212
233
|
};
|
213
234
|
|
235
|
+
ABCJS.write.AbstractEngraver.prototype.saveState = function() {
|
236
|
+
this.tiesSave = ABCJS.parse.cloneArray(this.ties);
|
237
|
+
this.slursSave = ABCJS.parse.cloneHashOfHash(this.slurs);
|
238
|
+
this.slursbyvoiceSave = ABCJS.parse.cloneHashOfHash(this.slursbyvoice);
|
239
|
+
this.tiesbyvoiceSave = ABCJS.parse.cloneHashOfArrayOfHash(this.tiesbyvoice);
|
240
|
+
};
|
241
|
+
|
242
|
+
ABCJS.write.AbstractEngraver.prototype.restoreState = function() {
|
243
|
+
this.ties = ABCJS.parse.cloneArray(this.tiesSave);
|
244
|
+
this.slurs = ABCJS.parse.cloneHashOfHash(this.slursSave);
|
245
|
+
this.slursbyvoice = ABCJS.parse.cloneHashOfHash(this.slursbyvoiceSave);
|
246
|
+
this.tiesbyvoice = ABCJS.parse.cloneHashOfArrayOfHash(this.tiesbyvoiceSave);
|
247
|
+
};
|
214
248
|
|
215
249
|
// return an array of ABCJS.write.AbsoluteElement
|
216
250
|
ABCJS.write.AbstractEngraver.prototype.createABCElement = function() {
|
@@ -225,17 +259,17 @@ ABCJS.write.AbstractEngraver.prototype.createABCElement = function() {
|
|
225
259
|
if (this.voice.duplicate) elemset[0].invisible = true;
|
226
260
|
break;
|
227
261
|
case "meter":
|
228
|
-
elemset[0] = ABCJS.write.createTimeSignature(elem);
|
262
|
+
elemset[0] = ABCJS.write.createTimeSignature(elem, this.tuneNumber);
|
229
263
|
this.startlimitelem = elemset[0]; // limit ties here
|
230
264
|
if (this.voice.duplicate) elemset[0].invisible = true;
|
231
265
|
break;
|
232
266
|
case "clef":
|
233
|
-
elemset[0] = ABCJS.write.createClef(elem);
|
267
|
+
elemset[0] = ABCJS.write.createClef(elem, this.tuneNumber);
|
234
268
|
if (!elemset[0]) return null;
|
235
269
|
if (this.voice.duplicate) elemset[0].invisible = true;
|
236
270
|
break;
|
237
271
|
case "key":
|
238
|
-
var absKey = ABCJS.write.createKeySignature(elem);
|
272
|
+
var absKey = ABCJS.write.createKeySignature(elem, this.tuneNumber);
|
239
273
|
if (absKey) {
|
240
274
|
elemset[0] = absKey;
|
241
275
|
this.startlimitelem = elemset[0]; // limit ties here
|
@@ -246,14 +280,14 @@ ABCJS.write.AbstractEngraver.prototype.createABCElement = function() {
|
|
246
280
|
this.stemdir=elem.direction;
|
247
281
|
break;
|
248
282
|
case "part":
|
249
|
-
var abselem = new ABCJS.write.AbsoluteElement(elem,0,0, 'part');
|
283
|
+
var abselem = new ABCJS.write.AbsoluteElement(elem,0,0, 'part', this.tuneNumber);
|
250
284
|
var dim = this.renderer.getTextSize(elem.title, 'partsfont', "part");
|
251
285
|
abselem.addChild(new ABCJS.write.RelativeElement(elem.title, 0, 0, undefined, {type:"part", height: dim.height/ABCJS.write.spacing.STEP}));
|
252
286
|
elemset[0] = abselem;
|
253
287
|
break;
|
254
288
|
case "tempo":
|
255
|
-
var abselem3 = new ABCJS.write.AbsoluteElement(elem,0,0, 'tempo');
|
256
|
-
abselem3.addChild(new ABCJS.write.TempoElement(elem));
|
289
|
+
var abselem3 = new ABCJS.write.AbsoluteElement(elem,0,0, 'tempo', this.tuneNumber);
|
290
|
+
abselem3.addChild(new ABCJS.write.TempoElement(elem, this.tuneNumber));
|
257
291
|
elemset[0] = abselem3;
|
258
292
|
break;
|
259
293
|
case "style":
|
@@ -262,8 +296,12 @@ ABCJS.write.AbstractEngraver.prototype.createABCElement = function() {
|
|
262
296
|
else
|
263
297
|
this.style = elem.head;
|
264
298
|
break;
|
299
|
+
case "hint":
|
300
|
+
ABCJS.write.hint = true;
|
301
|
+
this.saveState();
|
302
|
+
break;
|
265
303
|
default:
|
266
|
-
var abselem2 = new ABCJS.write.AbsoluteElement(elem,0,0, 'unsupported');
|
304
|
+
var abselem2 = new ABCJS.write.AbsoluteElement(elem,0,0, 'unsupported', this.tuneNumber);
|
267
305
|
abselem2.addChild(new ABCJS.write.RelativeElement("element type "+elem.el_type, 0, 0, undefined, {type:"debug"}));
|
268
306
|
elemset[0] = abselem2;
|
269
307
|
}
|
@@ -296,6 +334,7 @@ ABCJS.write.AbstractEngraver.prototype.createBeam = function() {
|
|
296
334
|
if (this.getElem().startBeam && !this.getElem().endBeam) {
|
297
335
|
var dir = this.calcBeamDir();
|
298
336
|
var beamelem = new ABCJS.write.BeamElem(this.stemHeight, dir);
|
337
|
+
if (ABCJS.write.hint) beamelem.setHint();
|
299
338
|
var oldDir = this.stemdir;
|
300
339
|
this.stemdir = dir;
|
301
340
|
while (this.getElem()) {
|
@@ -360,8 +399,8 @@ ABCJS.write.AbstractEngraver.prototype.createNote = function(elem, nostem, dontD
|
|
360
399
|
}
|
361
400
|
|
362
401
|
|
363
|
-
var abselem = new ABCJS.write.AbsoluteElement(elem, duration * this.tripletmultiplier, 1, 'note');
|
364
|
-
|
402
|
+
var abselem = new ABCJS.write.AbsoluteElement(elem, duration * this.tripletmultiplier, 1, 'note', this.tuneNumber);
|
403
|
+
if (ABCJS.write.hint) abselem.setHint();
|
365
404
|
|
366
405
|
if (elem.rest) {
|
367
406
|
var restpitch = 7;
|
@@ -542,6 +581,7 @@ ABCJS.write.AbstractEngraver.prototype.createNote = function(elem, nostem, dontD
|
|
542
581
|
var gracebeam = null;
|
543
582
|
if (elem.gracenotes.length>1) {
|
544
583
|
gracebeam = new ABCJS.write.BeamElem(this.stemHeight*graceScaleStem, "grace",this.isBagpipes);
|
584
|
+
if (ABCJS.write.hint) gracebeam.setHint();
|
545
585
|
gracebeam.mainNote = abselem; // this gives us a reference back to the note this is attached to so that the stems can be attached somewhere.
|
546
586
|
}
|
547
587
|
|
@@ -774,7 +814,9 @@ ABCJS.write.AbstractEngraver.prototype.createNoteHead = function(abselem, c, pit
|
|
774
814
|
if (pitchelem.startTie) {
|
775
815
|
//PER: bug fix: var tie = new ABCJS.write.TieElem(notehead, null, (this.stemdir=="up" || dir=="down") && this.stemdir!="down",(this.stemdir=="down" || this.stemdir=="up"));
|
776
816
|
var tie = new ABCJS.write.TieElem(notehead, null, (this.stemdir==="down" || dir==="down") && this.stemdir!=="up",(this.stemdir==="down" || this.stemdir==="up"), true);
|
777
|
-
|
817
|
+
if (ABCJS.write.hint) tie.setHint();
|
818
|
+
|
819
|
+
this.ties[this.ties.length]=tie;
|
778
820
|
this.voice.addOther(tie);
|
779
821
|
// HACK-PER: For the animation, we need to know if a note is tied to the next one, so here's a flag.
|
780
822
|
// Unfortunately, only some of the notes in the current event might be tied, but this will consider it
|
@@ -792,6 +834,7 @@ ABCJS.write.AbstractEngraver.prototype.createNoteHead = function(abselem, c, pit
|
|
792
834
|
delete this.slurs[slurid];
|
793
835
|
} else {
|
794
836
|
slur = new ABCJS.write.TieElem(null, notehead, dir==="down",(this.stemdir==="up" || dir==="down") && this.stemdir!=="down", false);
|
837
|
+
if (ABCJS.write.hint) slur.setHint();
|
795
838
|
this.voice.addOther(slur);
|
796
839
|
}
|
797
840
|
if (this.startlimitelem) {
|
@@ -805,6 +848,7 @@ ABCJS.write.AbstractEngraver.prototype.createNoteHead = function(abselem, c, pit
|
|
805
848
|
var slurid = pitchelem.startSlur[i].label;
|
806
849
|
//PER: bug fix: var slur = new ABCJS.write.TieElem(notehead, null, (this.stemdir=="up" || dir=="down") && this.stemdir!="down", this.stemdir);
|
807
850
|
var slur = new ABCJS.write.TieElem(notehead, null, (this.stemdir==="down" || dir==="down") && this.stemdir!=="up", false, false);
|
851
|
+
if (ABCJS.write.hint) slur.setHint();
|
808
852
|
this.slurs[slurid]=slur;
|
809
853
|
this.voice.addOther(slur);
|
810
854
|
}
|
@@ -814,13 +858,21 @@ ABCJS.write.AbstractEngraver.prototype.createNoteHead = function(abselem, c, pit
|
|
814
858
|
|
815
859
|
};
|
816
860
|
|
861
|
+
ABCJS.write.AbstractEngraver.prototype.addMeasureNumber = function (number, abselem) {
|
862
|
+
var measureNumHeight = this.renderer.getTextSize(number, "measurefont", 'bar-number');
|
863
|
+
abselem.addChild(new ABCJS.write.RelativeElement(number, 0, 0, 11+measureNumHeight.height / ABCJS.write.spacing.STEP, {type:"barNumber"}));
|
864
|
+
};
|
865
|
+
|
817
866
|
ABCJS.write.AbstractEngraver.prototype.createBarLine = function (elem) {
|
818
867
|
// bar_thin, bar_thin_thick, bar_thin_thin, bar_thick_thin, bar_right_repeat, bar_left_repeat, bar_double_repeat
|
819
868
|
|
820
|
-
var abselem = new ABCJS.write.AbsoluteElement(elem, 0, 10, 'bar');
|
869
|
+
var abselem = new ABCJS.write.AbsoluteElement(elem, 0, 10, 'bar', this.tuneNumber);
|
821
870
|
var anchor = null; // place to attach part lines
|
822
871
|
var dx = 0;
|
823
872
|
|
873
|
+
if (elem.barNumber) {
|
874
|
+
this.addMeasureNumber(elem.barNumber, abselem);
|
875
|
+
}
|
824
876
|
|
825
877
|
|
826
878
|
var firstdots = (elem.type==="bar_right_repeat" || elem.type==="bar_dbl_repeat");
|