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
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2c266341445b98625e0ab4b98abcb6cdf4af18ae
|
4
|
+
data.tar.gz: c24e3d239349217bb149896dc3ff3221a949117e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3ef48f03107fe57ba9c878decadacaf0c311a53db60f3a8f789b7387cd8d9304b5cdffcbf88e10db17a67794e83c34c380303078367d6995b5ea9dbfae121f94
|
7
|
+
data.tar.gz: e6fe7d8d56bc43083acb6b37f72a966b7803b546ebb84cb3b0f0da8e8caf8f1d1f4dd2ba5b513c8a8312a5aec76ce6513aa2cebca140669e7252e902d2d5d9d3
|
@@ -39,6 +39,28 @@ if (!window.ABCJS)
|
|
39
39
|
return ret;
|
40
40
|
}
|
41
41
|
|
42
|
+
// This finds the place in the stylesheets that contain the rule that matches the selector.
|
43
|
+
// If that selector is not found, then it creates the rule.
|
44
|
+
// We are doing this so that we can use a transition for animating the scrolling.
|
45
|
+
function getCssRule(selector) {
|
46
|
+
var rule;
|
47
|
+
for (var i = 0; i < document.styleSheets.length && rule === undefined; i++) {
|
48
|
+
var css = document.styleSheets[i];
|
49
|
+
var rules = css.rules;
|
50
|
+
if (rules) {
|
51
|
+
for (var j = 0; j < rules.length && rule === undefined; j++) {
|
52
|
+
if (rules[j].selectorText && rules[j].selectorText === selector)
|
53
|
+
rule = rules[j];
|
54
|
+
}
|
55
|
+
}
|
56
|
+
}
|
57
|
+
if (!rule) {
|
58
|
+
document.styleSheets[0].insertRule(selector + " { }", 1);
|
59
|
+
return getCssRule(selector);
|
60
|
+
}
|
61
|
+
return rule;
|
62
|
+
}
|
63
|
+
|
42
64
|
function getBeatsPerMinute(tune, options) {
|
43
65
|
// We either want to run the timer once per measure or once per beat. If we run it once per beat we need a multiplier for the measures.
|
44
66
|
// So, first we figure out the beats per minute and the beats per measure, then depending on the type of animation, we can
|
@@ -55,6 +77,13 @@ if (!window.ABCJS)
|
|
55
77
|
return bpm;
|
56
78
|
}
|
57
79
|
|
80
|
+
var scrollTimer;
|
81
|
+
var animateTimer;
|
82
|
+
var cssRule;
|
83
|
+
var currentMargin;
|
84
|
+
var animationTarget;
|
85
|
+
var shouldResetOverflow;
|
86
|
+
|
58
87
|
// This is a way to manipulate the written music on a timer. Their are two ways to manipulate the music: turn off each measure as it goes by,
|
59
88
|
// and put a vertical cursor before the next note to play. The timer works at the speed of the original tempo of the music unless it is overwritten
|
60
89
|
// in the options parameter.
|
@@ -66,8 +95,20 @@ if (!window.ABCJS)
|
|
66
95
|
// hideFinishedMeasures: true or false [ false is the default ]
|
67
96
|
// showCursor: true or false [ false is the default ]
|
68
97
|
// bpm: number of beats per minute [ the default is whatever is in the Q: field ]
|
98
|
+
// scrollHorizontal: true or false [ false is the default ]
|
99
|
+
// scrollVertical: true or false [ false is the default ]
|
100
|
+
// scrollHint: true or false [ false is the default ]
|
101
|
+
//
|
102
|
+
// If scrollHorizontal is present, then we expect that the music was rendered with the viewportHorizontal parameter so there is a viewport wrapping the music div. (Note that this only works when there is a single line of music and there are no repeats, signo, or codas.)
|
103
|
+
// If scrollVertical or scrollHint is present, then we expect that the music was rendered with the viewportVertical parameter so there is a viewport wrapping the music div.
|
104
|
+
// If the music is larger than the viewport, then it scrolls as the music is being played.
|
69
105
|
var stopNextTime = false;
|
70
106
|
var cursor;
|
107
|
+
|
108
|
+
function setMargin(margin) {
|
109
|
+
cssRule.style.marginTop = -margin + "px";
|
110
|
+
currentMargin = margin;
|
111
|
+
}
|
71
112
|
ABCJS.startAnimation = function(paper, tune, options) {
|
72
113
|
if (paper.getElementsByClassName === undefined) {
|
73
114
|
console.error("ABCJS.startAnimation: The first parameter must be a regular DOM element. (Did you pass a jQuery object or an ID?)");
|
@@ -77,6 +118,25 @@ if (!window.ABCJS)
|
|
77
118
|
console.error("ABCJS.startAnimation: The second parameter must be a single tune. (Did you pass the entire array of tunes?)");
|
78
119
|
return;
|
79
120
|
}
|
121
|
+
if (options.scrollHorizontal || options.scrollVertical || options.scrollHint) {
|
122
|
+
// We assume that there is an extra div in this case, so adjust the paper if needed.
|
123
|
+
// This can be called either with the outer div or the inner div.
|
124
|
+
if (!hasClass(paper, 'abcjs-inner')) {
|
125
|
+
// Must be the outer div; hide the scrollbar and move in.
|
126
|
+
paper.scrollTop = 0; // In case the user has repositioned the scrollbar.
|
127
|
+
paper.style.overflow = "hidden";
|
128
|
+
paper = paper.children[0];
|
129
|
+
}
|
130
|
+
if (!hasClass(paper, 'abcjs-inner')) {
|
131
|
+
console.error("ABCJS.startAnimation: When using scrollHorizontal/scrollVertical/scrollHint, the music must have been rendered using viewportHorizontal/viewportVertical.");
|
132
|
+
return;
|
133
|
+
}
|
134
|
+
}
|
135
|
+
// Can only have one animation at a time, so make sure that it has been stopped.
|
136
|
+
ABCJS.stopAnimation();
|
137
|
+
animationTarget = paper;
|
138
|
+
shouldResetOverflow = options.scrollVertical || options.scrollHint;
|
139
|
+
|
80
140
|
if (options.showCursor) {
|
81
141
|
cursor = $('<div class="cursor" style="position: absolute;"></div>');
|
82
142
|
$(paper).append(cursor);
|
@@ -87,9 +147,40 @@ if (!window.ABCJS)
|
|
87
147
|
var beatsPerMinute = getBeatsPerMinute(tune, options);
|
88
148
|
var beatsPerMillisecond = beatsPerMinute / 60000;
|
89
149
|
var beatLength = tune.getBeatLength(); // This is the same units as the duration is stored in.
|
150
|
+
var totalBeats = 0;
|
151
|
+
|
152
|
+
var millisecondsPerHalfMeasure;
|
153
|
+
if (options.scrollVertical) {
|
154
|
+
var millisecondsPerBeat = 1/beatsPerMillisecond;
|
155
|
+
var beatsPerMeasure = 1/beatLength;
|
156
|
+
var millisecondsPerMeasure = millisecondsPerBeat * beatsPerMeasure;
|
157
|
+
millisecondsPerHalfMeasure = millisecondsPerMeasure / 2;
|
158
|
+
cssRule = getCssRule(".abcjs-inner");
|
159
|
+
}
|
90
160
|
|
91
161
|
var startTime;
|
92
162
|
|
163
|
+
var initialWait = 2700;
|
164
|
+
var interval = 11;
|
165
|
+
var distance = 1;
|
166
|
+
var outer = paper.parentNode;
|
167
|
+
function scrolling() {
|
168
|
+
var currentPosition = paper.style.marginLeft;
|
169
|
+
if (currentPosition === "")
|
170
|
+
currentPosition = 0;
|
171
|
+
else
|
172
|
+
currentPosition = parseInt(currentPosition);
|
173
|
+
currentPosition -= distance;
|
174
|
+
paper.style.marginLeft = currentPosition + "px";
|
175
|
+
if (currentPosition > outer.offsetWidth - paper.scrollWidth)
|
176
|
+
scrollTimer = setTimeout(scrolling, interval);
|
177
|
+
}
|
178
|
+
|
179
|
+
if (options.scrollHorizontal) {
|
180
|
+
paper.style.marginLeft = "0px";
|
181
|
+
scrollTimer = setTimeout(scrolling, initialWait);
|
182
|
+
}
|
183
|
+
|
93
184
|
function processMeasureHider(lineNum, measureNum) {
|
94
185
|
var els = getAllElementsByClasses(paper, "l"+lineNum, "m"+measureNum);
|
95
186
|
|
@@ -102,6 +193,29 @@ if (!window.ABCJS)
|
|
102
193
|
}
|
103
194
|
}
|
104
195
|
|
196
|
+
function addVerticalInfo(timingEvents) {
|
197
|
+
// Add vertical info to the bar events: put the next event's top, and the event after the next measure's top.
|
198
|
+
var lastBarTop;
|
199
|
+
var lastBarBottom;
|
200
|
+
var lastEventTop;
|
201
|
+
var lastEventBottom;
|
202
|
+
for (var e = timingEvents.length-1; e >= 0; e--) {
|
203
|
+
var ev = timingEvents[e];
|
204
|
+
if (ev.type === 'bar') {
|
205
|
+
ev.top = lastEventTop;
|
206
|
+
ev.nextTop = lastBarTop;
|
207
|
+
lastBarTop = lastEventTop;
|
208
|
+
|
209
|
+
ev.bottom = lastEventBottom;
|
210
|
+
ev.nextBottom = lastBarBottom;
|
211
|
+
lastBarBottom = lastEventBottom;
|
212
|
+
} else if (ev.type === 'event') {
|
213
|
+
lastEventTop = ev.top;
|
214
|
+
lastEventBottom = ev.top +ev.height;
|
215
|
+
}
|
216
|
+
}
|
217
|
+
}
|
218
|
+
|
105
219
|
function makeSortedArray(hash) {
|
106
220
|
var arr = [];
|
107
221
|
for (var k in hash) {
|
@@ -144,6 +258,8 @@ if (!window.ABCJS)
|
|
144
258
|
var elements = voices[v].children;
|
145
259
|
for (var elem=0; elem<elements.length; elem++) {
|
146
260
|
var element = elements[elem];
|
261
|
+
if (element.hint)
|
262
|
+
break;
|
147
263
|
if (element.duration > 0) {
|
148
264
|
// There are 3 possibilities here: the note could stand on its own, the note could be tied to the next,
|
149
265
|
// the note could be tied to the previous, and the note could be tied on both sides.
|
@@ -191,9 +307,32 @@ if (!window.ABCJS)
|
|
191
307
|
}
|
192
308
|
// now we have all the events, but if there are multiple voices then there may be events out of order or duplicated, so normalize it.
|
193
309
|
timingEvents = makeSortedArray(eventHash);
|
310
|
+
totalBeats = timingEvents[timingEvents.length-1].time / beatLength;
|
311
|
+
if (options.scrollVertical) {
|
312
|
+
addVerticalInfo(timingEvents);
|
313
|
+
}
|
194
314
|
}
|
195
315
|
setupEvents(tune.engraver);
|
196
316
|
|
317
|
+
function isEndOfLine(currentNote) {
|
318
|
+
return currentNote.top !== currentNote.nextTop && currentNote.nextTop !== undefined;
|
319
|
+
}
|
320
|
+
|
321
|
+
function shouldScroll(outer, scrollPos, currentNote) {
|
322
|
+
var height = parseInt(outer.clientHeight, 10);
|
323
|
+
var isVisible = currentNote.nextBottom - scrollPos < height;
|
324
|
+
//console.log("SCROLL: ", height, scrollPos, currentNote.nextTop, currentNote.nextBottom, isVisible);
|
325
|
+
return !isVisible;
|
326
|
+
}
|
327
|
+
|
328
|
+
var lastTop = -1;
|
329
|
+
var inner = $(outer).find(".abcjs-inner");
|
330
|
+
currentMargin = 0;
|
331
|
+
|
332
|
+
if (options.scrollVertical) {
|
333
|
+
setMargin(0); // In case we are calling this a second time.
|
334
|
+
}
|
335
|
+
|
197
336
|
function processShowCursor() {
|
198
337
|
var currentNote = timingEvents.shift();
|
199
338
|
if (!currentNote) {
|
@@ -201,14 +340,31 @@ if (!window.ABCJS)
|
|
201
340
|
return 0;
|
202
341
|
}
|
203
342
|
if (currentNote.type === "bar") {
|
343
|
+
if (options.scrollVertical) {
|
344
|
+
if (isEndOfLine(currentNote) && shouldScroll(outer, currentMargin, currentNote)) {
|
345
|
+
setTimeout(function() {
|
346
|
+
setMargin(currentNote.nextTop);
|
347
|
+
}, millisecondsPerHalfMeasure);
|
348
|
+
}
|
349
|
+
}
|
204
350
|
if (options.hideFinishedMeasures)
|
205
351
|
processMeasureHider(currentNote.lineNum, currentNote.measureNum);
|
206
352
|
if (timingEvents.length > 0)
|
207
353
|
return timingEvents[0].time / beatLength;
|
208
354
|
return 0;
|
209
355
|
}
|
210
|
-
if (options.
|
211
|
-
|
356
|
+
if (options.scrollHint && lastTop !== currentNote.top) {
|
357
|
+
lastTop = currentNote.top;
|
358
|
+
setMargin(lastTop);
|
359
|
+
}
|
360
|
+
if (options.showCursor) {
|
361
|
+
cursor.css({
|
362
|
+
left: currentNote.left + "px",
|
363
|
+
top: currentNote.top + "px",
|
364
|
+
width: currentNote.width + "px",
|
365
|
+
height: currentNote.height + "px"
|
366
|
+
});
|
367
|
+
}
|
212
368
|
if (timingEvents.length > 0)
|
213
369
|
return timingEvents[0].time / beatLength;
|
214
370
|
stopNextTime = true;
|
@@ -228,7 +384,7 @@ if (!window.ABCJS)
|
|
228
384
|
if (interval <= 0)
|
229
385
|
processNext();
|
230
386
|
else
|
231
|
-
setTimeout(processNext, interval);
|
387
|
+
animateTimer = setTimeout(processNext, interval);
|
232
388
|
}
|
233
389
|
startTime = new Date();
|
234
390
|
startTime = startTime.getTime();
|
@@ -236,10 +392,16 @@ if (!window.ABCJS)
|
|
236
392
|
};
|
237
393
|
|
238
394
|
ABCJS.stopAnimation = function() {
|
239
|
-
|
395
|
+
clearTimeout(animateTimer);
|
396
|
+
clearTimeout(scrollTimer);
|
240
397
|
if (cursor) {
|
241
398
|
cursor.remove();
|
242
399
|
cursor = null;
|
243
400
|
}
|
401
|
+
if (shouldResetOverflow) {
|
402
|
+
if (animationTarget && animationTarget.parentNode) // If the music was redrawn or otherwise disappeared before the animation was finished, this might be null.
|
403
|
+
animationTarget.parentNode.style.overflowY = "auto";
|
404
|
+
setMargin(0);
|
405
|
+
}
|
244
406
|
};
|
245
407
|
})();
|
@@ -21,6 +21,8 @@ if (!window.ABCJS)
|
|
21
21
|
window.ABCJS = {};
|
22
22
|
|
23
23
|
(function() {
|
24
|
+
"use strict";
|
25
|
+
|
24
26
|
ABCJS.numberOfTunes = function(abc) {
|
25
27
|
var tunes = abc.split("\nX:");
|
26
28
|
var num = tunes.length;
|
@@ -125,7 +127,7 @@ if (!window.ABCJS)
|
|
125
127
|
abcParser.parse(book.tunes[currentTune].abc, parserParams);
|
126
128
|
var tune = abcParser.getTune();
|
127
129
|
ret.push(tune);
|
128
|
-
callback(div, tune);
|
130
|
+
callback(div, tune, i);
|
129
131
|
}
|
130
132
|
}
|
131
133
|
currentTune++;
|
@@ -133,6 +135,132 @@ if (!window.ABCJS)
|
|
133
135
|
return ret;
|
134
136
|
}
|
135
137
|
|
138
|
+
var resizeDivs = {};
|
139
|
+
function resizeOuter() {
|
140
|
+
var width = window.innerWidth;
|
141
|
+
for (var id in resizeDivs) {
|
142
|
+
if (resizeDivs.hasOwnProperty(id)) {
|
143
|
+
var outer = resizeDivs[id];
|
144
|
+
var ofs = outer.offsetLeft;
|
145
|
+
width -= ofs * 2;
|
146
|
+
outer.style.width = width + "px";
|
147
|
+
}
|
148
|
+
}
|
149
|
+
}
|
150
|
+
|
151
|
+
window.addEventListener("resize", resizeOuter);
|
152
|
+
window.addEventListener("orientationChange", resizeOuter);
|
153
|
+
|
154
|
+
function renderOne(div, tune, renderParams, engraverParams) {
|
155
|
+
var width = renderParams.width ? renderParams.width : 800;
|
156
|
+
if (renderParams.viewportHorizontal) {
|
157
|
+
// Create an inner div that holds the music, so that the passed in div will be the viewport.
|
158
|
+
div.innerHTML = '<div class="abcjs-inner"></div>';
|
159
|
+
if (renderParams.scrollHorizontal) {
|
160
|
+
div.style.overflowX = "auto";
|
161
|
+
div.style.overflowY = "hidden";
|
162
|
+
} else
|
163
|
+
div.style.overflow = "hidden";
|
164
|
+
resizeDivs[div.id] = div; // We use a hash on the element's id so that multiple calls won't keep adding to the list.
|
165
|
+
div = div.children[0]; // The music should be rendered in the inner div.
|
166
|
+
}
|
167
|
+
else if (renderParams.viewportVertical) {
|
168
|
+
// Create an inner div that holds the music, so that the passed in div will be the viewport.
|
169
|
+
div.innerHTML = '<div class="abcjs-inner scroll-amount"></div>';
|
170
|
+
div.style.overflowX = "hidden";
|
171
|
+
div.style.overflowY = "auto";
|
172
|
+
div = div.children[0]; // The music should be rendered in the inner div.
|
173
|
+
}
|
174
|
+
/* jshint -W064 */ var paper = Raphael(div, width, 400); /* jshint +W064 */
|
175
|
+
if (engraverParams === undefined)
|
176
|
+
engraverParams = {};
|
177
|
+
var engraver_controller = new ABCJS.write.EngraverController(paper, engraverParams);
|
178
|
+
engraver_controller.engraveABC(tune);
|
179
|
+
tune.engraver = engraver_controller;
|
180
|
+
if (renderParams.viewportVertical || renderParams.viewportHorizontal) {
|
181
|
+
// If we added a wrapper around the div, then we need to size the wrapper, too.
|
182
|
+
var parent = div.parentNode;
|
183
|
+
parent.style.width = div.style.width;
|
184
|
+
}
|
185
|
+
}
|
186
|
+
|
187
|
+
function renderEachLineSeparately(div, tune, renderParams, engraverParams) {
|
188
|
+
function initializeTuneLine(tune) {
|
189
|
+
return {
|
190
|
+
formatting: tune.formatting,
|
191
|
+
media: tune.media,
|
192
|
+
version: tune.version,
|
193
|
+
metaText: {},
|
194
|
+
lines: []
|
195
|
+
};
|
196
|
+
}
|
197
|
+
|
198
|
+
// Before rendering, chop up the returned tune into an array where each element is a line.
|
199
|
+
// The first element of the array gets the title and other items that go on top, the last element
|
200
|
+
// of the array gets the extra text that goes on bottom. Each element gets any non-music info that comes before it.
|
201
|
+
var tunes = [];
|
202
|
+
var tuneLine;
|
203
|
+
for (var i = 0; i < tune.lines.length; i++) {
|
204
|
+
var line = tune.lines[i];
|
205
|
+
if (!tuneLine)
|
206
|
+
tuneLine = initializeTuneLine(tune);
|
207
|
+
|
208
|
+
if (i === 0) {
|
209
|
+
// These items go on top of the music
|
210
|
+
tuneLine.metaText.tempo = tune.metaText.tempo;
|
211
|
+
tuneLine.metaText.title = tune.metaText.title;
|
212
|
+
tuneLine.metaText.header = tune.metaText.header;
|
213
|
+
tuneLine.metaText.rhythm = tune.metaText.rhythm;
|
214
|
+
tuneLine.metaText.origin = tune.metaText.origin;
|
215
|
+
tuneLine.metaText.composer = tune.metaText.composer;
|
216
|
+
tuneLine.metaText.author = tune.metaText.author;
|
217
|
+
tuneLine.metaText.partOrder = tune.metaText.partOrder;
|
218
|
+
}
|
219
|
+
|
220
|
+
// push the lines until we get to a music line
|
221
|
+
tuneLine.lines.push(line);
|
222
|
+
if (line.staff) {
|
223
|
+
tunes.push(tuneLine);
|
224
|
+
tuneLine = undefined;
|
225
|
+
}
|
226
|
+
}
|
227
|
+
// Add any extra stuff to the last line.
|
228
|
+
if (tuneLine) {
|
229
|
+
var lastLine = tunes[tunes.length-1];
|
230
|
+
for (var j = 0; j < tuneLine.lines.length; j++)
|
231
|
+
lastLine.lines.push(tuneLine.lines[j]);
|
232
|
+
}
|
233
|
+
|
234
|
+
// These items go below the music
|
235
|
+
tuneLine = tunes[tunes.length-1];
|
236
|
+
tuneLine.metaText.unalignedWords = tune.metaText.unalignedWords;
|
237
|
+
tuneLine.metaText.book = tune.metaText.book;
|
238
|
+
tuneLine.metaText.source = tune.metaText.source;
|
239
|
+
tuneLine.metaText.discography = tune.metaText.discography;
|
240
|
+
tuneLine.metaText.notes = tune.metaText.notes;
|
241
|
+
tuneLine.metaText.transcription = tune.metaText.transcription;
|
242
|
+
tuneLine.metaText.history = tune.metaText.history;
|
243
|
+
tuneLine.metaText['abc-copyright'] = tune.metaText['abc-copyright'];
|
244
|
+
tuneLine.metaText['abc-creator'] = tune.metaText['abc-creator'];
|
245
|
+
tuneLine.metaText['abc-edited-by'] = tune.metaText['abc-edited-by'];
|
246
|
+
tuneLine.metaText.footer = tune.metaText.footer;
|
247
|
+
|
248
|
+
// Now create sub-divs and render each line
|
249
|
+
var eParamsFirst = JSON.parse(JSON.stringify(engraverParams));
|
250
|
+
var eParamsMid = JSON.parse(JSON.stringify(engraverParams));
|
251
|
+
var eParamsLast = JSON.parse(JSON.stringify(engraverParams));
|
252
|
+
eParamsFirst.paddingbottom = -20;
|
253
|
+
eParamsMid.paddingbottom = -20;
|
254
|
+
eParamsMid.paddingtop = 10;
|
255
|
+
eParamsLast.paddingtop = 10;
|
256
|
+
for (var k = 0; k < tunes.length; k++) {
|
257
|
+
var lineEl = document.createElement("div");
|
258
|
+
div.appendChild(lineEl);
|
259
|
+
var ep = (k === 0) ? eParamsFirst : (k === tunes.length-1) ? eParamsLast : eParamsMid;
|
260
|
+
renderOne(lineEl, tunes[k], renderParams, ep);
|
261
|
+
}
|
262
|
+
}
|
263
|
+
|
136
264
|
// A quick way to render a tune from javascript when interactivity is not required.
|
137
265
|
// This is used when a javascript routine has some abc text that it wants to render
|
138
266
|
// in a div or collection of divs. One tune or many can be rendered.
|
@@ -151,14 +279,13 @@ if (!window.ABCJS)
|
|
151
279
|
// (If this element is not present, then rendering starts at zero.)
|
152
280
|
// width: 800 by default. The width in pixels of the output paper
|
153
281
|
ABCJS.renderAbc = function(output, abc, parserParams, engraverParams, renderParams) {
|
282
|
+
if (renderParams === undefined)
|
283
|
+
renderParams = {};
|
154
284
|
function callback(div, tune) {
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
var engraver_controller = new ABCJS.write.EngraverController(paper, engraverParams);
|
160
|
-
engraver_controller.engraveABC(tune);
|
161
|
-
tune.engraver = engraver_controller;
|
285
|
+
if (!renderParams.oneSvgPerLine || tune.lines.length < 2)
|
286
|
+
renderOne(div, tune, renderParams, engraverParams);
|
287
|
+
else
|
288
|
+
renderEachLineSeparately(div, tune, renderParams, engraverParams);
|
162
289
|
}
|
163
290
|
|
164
291
|
return renderEngine(callback, output, abc, parserParams, renderParams);
|
@@ -181,14 +308,42 @@ if (!window.ABCJS)
|
|
181
308
|
// startingTune: an index, starting at zero, representing which tune to start rendering at.
|
182
309
|
// (If this element is not present, then rendering starts at zero.)
|
183
310
|
ABCJS.renderMidi = function(output, abc, parserParams, midiParams, renderParams) {
|
184
|
-
|
185
|
-
|
186
|
-
|
311
|
+
if (midiParams === undefined)
|
312
|
+
midiParams = {};
|
313
|
+
if (midiParams.generateInline === undefined) // default is to generate inline controls.
|
314
|
+
midiParams.generateInline = true;
|
315
|
+
if (midiParams.inlineControls)
|
316
|
+
midiParams.inlineControls.selectionToggle = false; // Override the selection option because there is no selection in the Basic call.
|
317
|
+
|
318
|
+
function callback(div, tune, index) {
|
319
|
+
var html = "";
|
187
320
|
var midi = window.ABCJS.midi.create(tune, midiParams);
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
321
|
+
if (midiParams.generateInline) {
|
322
|
+
var inlineMidi = midi.inline ? midi.inline : midi;
|
323
|
+
html += window.ABCJS.midi.generateMidiControls(tune, midiParams, inlineMidi, index);
|
324
|
+
}
|
325
|
+
if (midiParams.generateDownload) {
|
326
|
+
var downloadMidi = midi.download ? midi.download : midi;
|
327
|
+
html += window.ABCJS.midi.generateMidiDownloadLink(tune, midiParams, downloadMidi, index);
|
328
|
+
}
|
329
|
+
div.innerHTML = html;
|
330
|
+
var find = function(element, cls) {
|
331
|
+
var els = element.getElementsByClassName(cls);
|
332
|
+
if (els.length === 0)
|
333
|
+
return null;
|
334
|
+
return els[0];
|
335
|
+
};
|
336
|
+
if (midiParams.generateInline && (midiParams.animate || midiParams.listener)) {
|
337
|
+
var parent = find(div, "abcjs-inline-midi");
|
338
|
+
parent.abcjsTune = tune;
|
339
|
+
parent.abcjsListener = midiParams.listener;
|
340
|
+
parent.abcjsAnimate = midiParams.animate;
|
341
|
+
}
|
342
|
+
if (midiParams.generateInline && midiParams.inlineControls && midiParams.inlineControls.startPlaying) {
|
343
|
+
var startButton = find(div, "abcjs-midi-start");
|
344
|
+
window.ABCJS.midi.startPlaying(startButton);
|
345
|
+
}
|
346
|
+
|
192
347
|
}
|
193
348
|
|
194
349
|
return renderEngine(callback, output, abc, parserParams, renderParams);
|