abcjs-rails 2.3 → 3.0
Sign up to get free protection for your applications and to get access to all the features.
- 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);
|