abcjs 6.0.0-beta.7 → 6.0.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.
- package/.github/workflows/tests.yml +29 -0
- package/CODE_OF_CONDUCT.md +76 -0
- package/CONTRIBUTING.md +1 -0
- package/LICENSE.md +1 -1
- package/README.md +92 -3
- package/RELEASE.md +957 -1
- package/abcjs-audio.css +14 -5
- package/dist/.gitignore +1 -2
- package/dist/abcjs-basic-min.js +3 -0
- package/dist/abcjs-basic-min.js.LICENSE +23 -0
- package/dist/abcjs-basic.js +28231 -0
- package/dist/abcjs-basic.js.map +1 -0
- package/dist/abcjs-plugin-min.js +3 -0
- package/dist/abcjs-plugin-min.js.LICENSE +23 -0
- package/dist/report-basic.html +37 -0
- package/dist/report-before-glyph-compress.html +37 -0
- package/dist/report-brown-ts-target-es5.html +37 -0
- package/dist/report-dev-orig-no-babel.html +37 -0
- package/dist/report-synth.html +37 -0
- package/docker-build.sh +1 -0
- package/glyphs.json +1 -0
- package/index.js +27 -2
- package/{static-wrappers/license.js → license.js} +1 -1
- package/package.json +26 -29
- package/{src/plugin/abc_plugin.js → plugin.js} +31 -19
- package/src/api/abc_animation.js +1 -17
- package/src/api/abc_tablatures.js +144 -0
- package/src/api/abc_timing_callbacks.js +234 -116
- package/src/api/abc_tunebook.js +18 -67
- package/src/api/abc_tunebook_svg.js +38 -46
- package/src/data/abc_tune.js +232 -972
- package/src/data/deline-tune.js +199 -0
- package/src/edit/abc_editarea.js +112 -0
- package/src/edit/abc_editor.js +95 -221
- package/src/midi/abc_midi_create.js +48 -50
- package/src/parse/abc_common.js +0 -14
- package/src/parse/abc_parse.js +167 -1321
- package/src/parse/abc_parse_book.js +62 -0
- package/src/parse/abc_parse_directive.js +164 -41
- package/src/parse/abc_parse_header.js +116 -145
- package/src/parse/abc_parse_key_voice.js +26 -20
- package/src/parse/abc_parse_music.js +1337 -0
- package/src/parse/abc_tokenizer.js +21 -15
- package/src/parse/abc_transpose.js +3 -15
- package/src/parse/tune-builder.js +896 -0
- package/src/parse/wrap_lines.js +205 -453
- package/src/synth/abc_midi_flattener.js +1292 -0
- package/src/{midi → synth}/abc_midi_renderer.js +44 -17
- package/src/synth/abc_midi_sequencer.js +648 -0
- package/src/synth/active-audio-context.js +3 -14
- package/src/synth/cents-to-factor.js +10 -0
- package/src/synth/create-note-map.js +21 -32
- package/src/synth/create-synth-control.js +20 -103
- package/src/synth/create-synth.js +185 -77
- package/src/synth/download-buffer.js +7 -21
- package/src/synth/get-midi-file.js +13 -20
- package/src/synth/images/{loading.svg → loading.svg.js} +4 -0
- package/src/synth/images/loop.svg.js +65 -0
- package/src/synth/images/pause.svg.js +10 -0
- package/src/synth/images/play.svg.js +9 -0
- package/src/synth/images/{reset.svg → reset.svg.js} +5 -1
- package/src/synth/instrument-index-to-name.js +1 -16
- package/src/synth/load-note.js +37 -76
- package/src/synth/pitch-to-note-name.js +0 -15
- package/src/synth/pitches-to-perc.js +64 -0
- package/src/synth/place-note.js +78 -68
- package/src/synth/play-event.js +17 -18
- package/src/synth/register-audio-context.js +11 -23
- package/src/synth/sounds-cache.js +0 -15
- package/src/synth/supports-audio.js +9 -23
- package/src/synth/synth-controller.js +80 -49
- package/src/synth/synth-sequence.js +20 -34
- package/src/tablatures/instruments/guitar/guitar-fonts.js +19 -0
- package/src/tablatures/instruments/guitar/guitar-patterns.js +23 -0
- package/src/tablatures/instruments/guitar/tab-guitar.js +50 -0
- package/src/tablatures/instruments/string-patterns.js +277 -0
- package/src/tablatures/instruments/string-tablature.js +56 -0
- package/src/tablatures/instruments/tab-note.js +282 -0
- package/src/tablatures/instruments/tab-notes.js +41 -0
- package/src/tablatures/instruments/violin/tab-violin.js +47 -0
- package/src/tablatures/instruments/violin/violin-fonts.js +19 -0
- package/src/tablatures/instruments/violin/violin-patterns.js +23 -0
- package/src/tablatures/tab-absolute-elements.js +310 -0
- package/src/tablatures/tab-common.js +29 -0
- package/src/tablatures/tab-renderer.js +243 -0
- package/src/tablatures/transposer.js +110 -0
- package/src/test/abc_midi_lint.js +5 -22
- package/src/test/abc_midi_sequencer_lint.js +11 -14
- package/src/test/abc_parser_lint.js +136 -32
- package/src/test/abc_vertical_lint.js +94 -32
- package/src/test/rendering-lint.js +38 -5
- package/src/write/abc_absolute_element.js +112 -120
- package/src/write/abc_abstract_engraver.js +102 -253
- package/src/write/abc_beam_element.js +30 -290
- package/src/write/abc_brace_element.js +12 -121
- package/src/write/abc_create_clef.js +21 -32
- package/src/write/abc_create_key_signature.js +8 -26
- package/src/write/abc_create_note_head.js +107 -0
- package/src/write/abc_create_time_signature.js +2 -21
- package/src/write/abc_crescendo_element.js +3 -50
- package/src/write/abc_decoration.js +7 -30
- package/src/write/abc_dynamic_decoration.js +3 -37
- package/src/write/abc_ending_element.js +1 -57
- package/src/write/abc_engraver_controller.js +111 -234
- package/src/write/abc_glyphs.js +9 -19
- package/src/write/abc_relative_element.js +57 -97
- package/src/write/abc_renderer.js +10 -832
- package/src/write/abc_spacing.js +0 -15
- package/src/write/abc_staff_group_element.js +14 -349
- package/src/write/abc_tempo_element.js +9 -117
- package/src/write/abc_tie_element.js +5 -68
- package/src/write/abc_triplet_element.js +6 -124
- package/src/write/abc_voice_element.js +7 -222
- package/src/write/add-chord.js +103 -0
- package/src/write/add-text-if.js +33 -0
- package/src/write/bottom-text.js +79 -0
- package/src/write/calcHeight.js +17 -0
- package/src/write/classes.js +100 -0
- package/src/write/draw/absolute.js +68 -0
- package/src/write/draw/beam.js +56 -0
- package/src/write/draw/brace.js +106 -0
- package/src/write/draw/crescendo.js +38 -0
- package/src/write/draw/debug-box.js +8 -0
- package/src/write/draw/draw.js +56 -0
- package/src/write/draw/dynamics.js +20 -0
- package/src/write/draw/ending.js +46 -0
- package/src/write/draw/group-elements.js +66 -0
- package/src/write/draw/horizontal-line.js +25 -0
- package/src/write/draw/non-music.js +50 -0
- package/src/write/draw/print-line.js +24 -0
- package/src/write/draw/print-path.js +7 -0
- package/src/write/draw/print-stem.js +30 -0
- package/src/write/draw/print-symbol.js +59 -0
- package/src/write/draw/print-vertical-line.js +18 -0
- package/src/write/draw/relative.js +77 -0
- package/src/write/draw/round-number.js +5 -0
- package/src/write/draw/selectables.js +59 -0
- package/src/write/draw/separator.js +16 -0
- package/src/write/draw/set-paper-size.js +45 -0
- package/src/write/{sprintf.js → draw/sprintf.js} +0 -0
- package/src/write/draw/staff-group.js +226 -0
- package/src/write/draw/staff-line.js +9 -0
- package/src/write/draw/staff.js +33 -0
- package/src/write/draw/tab-line.js +40 -0
- package/src/write/draw/tempo.js +45 -0
- package/src/write/draw/text.js +71 -0
- package/src/write/draw/tie.js +97 -0
- package/src/write/draw/triplet.js +46 -0
- package/src/write/draw/voice.js +102 -0
- package/src/write/format-jazz-chord.js +15 -0
- package/src/write/free-text.js +41 -0
- package/src/write/get-font-and-attr.js +37 -0
- package/src/write/get-text-size.js +56 -0
- package/src/write/highlight.js +11 -0
- package/src/write/layout/VoiceElements.js +121 -0
- package/src/write/layout/beam.js +213 -0
- package/src/write/layout/get-left-edge-of-staff.js +56 -0
- package/src/write/layout/getBarYAt.js +6 -0
- package/src/write/layout/layout.js +94 -0
- package/src/write/layout/setUpperAndLowerElements.js +232 -0
- package/src/write/layout/staffGroup.js +146 -0
- package/src/write/layout/triplet.js +75 -0
- package/src/write/layout/voice.js +137 -0
- package/src/write/selection.js +188 -70
- package/src/write/separator.js +10 -0
- package/src/write/set-class.js +21 -0
- package/src/write/subtitle.js +12 -0
- package/src/write/svg.js +95 -43
- package/src/write/top-text.js +54 -0
- package/src/write/unhighlight.js +11 -0
- package/temp.txt +17 -0
- package/test.js +27 -64
- package/types/index.d.ts +1095 -0
- package/version.js +1 -1
- package/.babelrc +0 -5
- package/.eslintrc +0 -3
- package/.gitmodules +0 -3
- package/abcjs-midi.css +0 -166
- package/build-utils/loadPresets.js +0 -14
- package/build-utils/presets/webpack.analyze.js +0 -6
- package/build-utils/presets/webpack.optimize.js +0 -30
- package/build-utils/webpack.development.js +0 -14
- package/build-utils/webpack.production.js +0 -35
- package/deploy-docs.sh +0 -25
- package/docs/README.md +0 -33
- package/fix-versions.sh +0 -23
- package/mei.js +0 -43
- package/midi.js +0 -62
- package/src/api/abc_tunebook_midi.js +0 -116
- package/src/midi/abc_midi_controls.js +0 -701
- package/src/midi/abc_midi_flattener.js +0 -1119
- package/src/midi/abc_midi_js_preparer.js +0 -243
- package/src/midi/abc_midi_sequencer.js +0 -401
- package/src/midi/abc_midi_ui_generator.js +0 -86
- package/src/plugin/abc_plugin_midi.js +0 -220
- package/src/synth/images/loop.svg +0 -61
- package/src/synth/images/pause.svg +0 -6
- package/src/synth/images/play.svg +0 -5
- package/src/transform/abc2abc_write.js +0 -395
- package/static-wrappers/basic.js +0 -2
- package/static-wrappers/midi.js +0 -2
- package/static-wrappers/plugin-midi.js +0 -6
- package/static-wrappers/plugin.js +0 -6
- package/webpack.config.js +0 -29
package/src/parse/wrap_lines.js
CHANGED
|
@@ -1,119 +1,161 @@
|
|
|
1
1
|
// wrap_lines.js: does line wrap on an already parsed tune.
|
|
2
|
-
// Copyright (C) 2018-2020 Paul Rosen (paul at paulrosen dot net)
|
|
3
|
-
//
|
|
4
|
-
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
|
|
5
|
-
// documentation files (the "Software"), to deal in the Software without restriction, including without limitation
|
|
6
|
-
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
|
|
7
|
-
// to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
8
|
-
//
|
|
9
|
-
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
10
|
-
//
|
|
11
|
-
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
|
|
12
|
-
// BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
13
|
-
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
|
14
|
-
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
15
|
-
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
16
2
|
|
|
17
|
-
function wrapLines(tune, lineBreaks) {
|
|
3
|
+
function wrapLines(tune, lineBreaks, barNumbers) {
|
|
18
4
|
if (!lineBreaks || tune.lines.length === 0)
|
|
19
5
|
return;
|
|
20
6
|
|
|
21
7
|
// tune.lines contains nested arrays: there is an array of lines (that's the part this function rewrites),
|
|
22
8
|
// there is an array of staffs per line (for instance, piano will have 2, orchestra will have many)
|
|
23
9
|
// there is an array of voices per staff (for instance, 4-part harmony might have bass and tenor on a single staff)
|
|
24
|
-
|
|
25
|
-
var
|
|
26
|
-
//
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
var measureMarker = [];
|
|
31
|
-
var lastMeter = '';
|
|
32
|
-
var voiceStart = {};
|
|
33
|
-
var linesWithoutStaff = 0;
|
|
10
|
+
var lines = tune.deline({lineBreaks: false});
|
|
11
|
+
var linesBreakElements = findLineBreaks(lines, lineBreaks);
|
|
12
|
+
//console.log(JSON.stringify(linesBreakElements))
|
|
13
|
+
tune.lines = addLineBreaks(lines, linesBreakElements, barNumbers);
|
|
14
|
+
tune.lineBreaks = linesBreakElements;
|
|
15
|
+
}
|
|
34
16
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
17
|
+
function addLineBreaks(lines, linesBreakElements, barNumbers) {
|
|
18
|
+
// linesBreakElements is an array of all of the elements that break for a new line
|
|
19
|
+
// The objects in the array look like:
|
|
20
|
+
// {"ogLine":0,"line":0,"staff":0,"voice":0,"start":0, "end":21}
|
|
21
|
+
// ogLine is the original line that it came from,
|
|
22
|
+
// line is the target line.
|
|
23
|
+
// then copy all the elements from start to end for the staff and voice specified.
|
|
24
|
+
// If the item doesn't contain "staff" then it is a non music line and should just be copied.
|
|
25
|
+
var outputLines = [];
|
|
26
|
+
var lastKeySig = []; // This is per staff - if the key changed then this will be populated.
|
|
27
|
+
var lastStem = [];
|
|
28
|
+
var currentBarNumber = 1;
|
|
29
|
+
for (var i = 0; i < linesBreakElements.length; i++) {
|
|
30
|
+
var action = linesBreakElements[i];
|
|
31
|
+
if (lines[action.ogLine].staff) {
|
|
32
|
+
var inputStaff = lines[action.ogLine].staff[action.staff];
|
|
33
|
+
if (!outputLines[action.line]) {
|
|
34
|
+
outputLines[action.line] = {staff: []}
|
|
35
|
+
}
|
|
36
|
+
if (!outputLines[action.line].staff[action.staff]) {
|
|
37
|
+
outputLines[action.line].staff[action.staff] = {voices: []};
|
|
38
|
+
if (barNumbers !== undefined && action.staff === 0 && action.line > 0) {
|
|
39
|
+
outputLines[action.line].staff[action.staff].barNumber = currentBarNumber;
|
|
45
40
|
}
|
|
46
|
-
var
|
|
47
|
-
var
|
|
48
|
-
|
|
49
|
-
if (
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
41
|
+
var keys = Object.keys(inputStaff)
|
|
42
|
+
for (var k = 0; k < keys.length; k++) {
|
|
43
|
+
var skip = keys[k] === "voices";
|
|
44
|
+
if (keys[k] === "meter" && action.line !== 0)
|
|
45
|
+
skip = true;
|
|
46
|
+
if (!skip)
|
|
47
|
+
outputLines[action.line].staff[action.staff][keys[k]] = inputStaff[keys[k]];
|
|
48
|
+
}
|
|
49
|
+
if (lastKeySig[action.staff])
|
|
50
|
+
outputLines[action.line].staff[action.staff].key = lastKeySig[action.staff];
|
|
51
|
+
|
|
52
|
+
}
|
|
53
|
+
if (!outputLines[action.line].staff[action.staff].voices[action.voice]) {
|
|
54
|
+
outputLines[action.line].staff[action.staff].voices[action.voice] = [];
|
|
55
|
+
}
|
|
56
|
+
outputLines[action.line].staff[action.staff].voices[action.voice] =
|
|
57
|
+
lines[action.ogLine].staff[action.staff].voices[action.voice].slice(action.start, action.end+1);
|
|
58
|
+
if (lastStem[action.staff*10+action.voice])
|
|
59
|
+
outputLines[action.line].staff[action.staff].voices[action.voice].unshift({el_type: "stem", direction: lastStem[action.staff*10+action.voice].direction})
|
|
60
|
+
var currVoice = outputLines[action.line].staff[action.staff].voices[action.voice];
|
|
61
|
+
for (var kk = currVoice.length-1; kk >= 0; kk--) {
|
|
62
|
+
if (currVoice[kk].el_type === "key") {
|
|
63
|
+
lastKeySig[action.staff] = {
|
|
64
|
+
root: currVoice[kk].root,
|
|
65
|
+
acc: currVoice[kk].acc,
|
|
66
|
+
mode: currVoice[kk].mode,
|
|
67
|
+
accidentals: currVoice[kk].accidentals.filter(function (acc) { return acc.acc !== 'natural' })
|
|
68
|
+
};
|
|
69
|
+
break;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
for (kk = currVoice.length-1; kk >= 0; kk--) {
|
|
73
|
+
if (currVoice[kk].el_type === "stem") {
|
|
74
|
+
lastStem[action.staff*10+action.voice] = {
|
|
75
|
+
direction: currVoice[kk].direction,
|
|
76
|
+
};
|
|
77
|
+
break;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
if (barNumbers !== undefined && action.staff === 0 && action.voice === 0) {
|
|
81
|
+
for (kk = 0; kk < currVoice.length; kk++) {
|
|
82
|
+
if (currVoice[kk].el_type === 'bar') {
|
|
83
|
+
currentBarNumber++
|
|
84
|
+
if (kk === currVoice.length-1)
|
|
85
|
+
delete currVoice[kk].barNumber
|
|
86
|
+
else
|
|
87
|
+
currVoice[kk].barNumber = currentBarNumber
|
|
54
88
|
}
|
|
55
|
-
|
|
56
|
-
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
} else {
|
|
92
|
+
outputLines[action.line] = lines[action.ogLine];
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
// There could be some missing info - if the tune passed in was incomplete or had different lengths for different voices or was missing a voice altogether - just fill in the gaps.
|
|
96
|
+
for (var ii = 0; ii < outputLines.length; ii++) {
|
|
97
|
+
if (outputLines[ii].staff) {
|
|
98
|
+
outputLines[ii].staff = outputLines[ii].staff.filter(function (el) {
|
|
99
|
+
return el != null;
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
return outputLines;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
function findLineBreaks(lines, lineBreakArray) {
|
|
108
|
+
// lineBreakArray is an array of all of the sections of the tune - often there will just be one
|
|
109
|
+
// section unless there is a subtitle or other non-music lines. Each of the elements of
|
|
110
|
+
// Each element of lineBreakArray is an array of the zero-based last measure of the line.
|
|
111
|
+
var lineBreakIndexes = [];
|
|
112
|
+
var lbai = 0;
|
|
113
|
+
var lineCounter = 0;
|
|
114
|
+
var outputLine = 0;
|
|
115
|
+
for (var i = 0; i < lines.length; i++) {
|
|
116
|
+
var line = lines[i];
|
|
117
|
+
if (line.staff) {
|
|
118
|
+
var lineStart = lineCounter;
|
|
119
|
+
var lineBreaks = lineBreakArray[lbai];
|
|
120
|
+
lbai++;
|
|
121
|
+
for (var j = 0; j < line.staff.length; j++) {
|
|
122
|
+
var staff = line.staff[j];
|
|
123
|
+
for (var k = 0; k < staff.voices.length; k++) {
|
|
124
|
+
outputLine = lineStart;
|
|
125
|
+
var measureNumber = 0;
|
|
126
|
+
var lbi = 0;
|
|
127
|
+
var voice = staff.voices[k];
|
|
128
|
+
var start = 0;
|
|
57
129
|
for (var e = 0; e < voice.length; e++) {
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
if (
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
lastMeter = JSON.stringify(staff[key]);
|
|
68
|
-
newLines[currentLine[j][k]].staff[j][key] = staff[key];
|
|
69
|
-
}
|
|
70
|
-
} else if (key !== 'voices') {
|
|
71
|
-
newLines[currentLine[j][k]].staff[j][key] = staff[key];
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
if (measureMarker[j][k])
|
|
77
|
-
newLines[currentLine[j][k]].staff[j].barNumber = measureMarker[j][k];
|
|
78
|
-
startNewLine[j][k] = false;
|
|
79
|
-
}
|
|
80
|
-
var element = voice[e];
|
|
81
|
-
if (!newLines[currentLine[j][k]].staff[j].voices[k]) {
|
|
82
|
-
newLines[currentLine[j][k]].staff[j].voices[k] = [];
|
|
83
|
-
for (var startItem in voiceStart) {
|
|
84
|
-
if (voiceStart.hasOwnProperty(startItem)) {
|
|
85
|
-
newLines[currentLine[j][k]].staff[j].voices[k].push(voiceStart[startItem])
|
|
86
|
-
}
|
|
130
|
+
var el = voice[e];
|
|
131
|
+
|
|
132
|
+
if (el.el_type === 'bar') {
|
|
133
|
+
if (lineBreaks[lbi] === measureNumber) {
|
|
134
|
+
lineBreakIndexes.push({ ogLine: i, line: outputLine, staff: j, voice: k, start: start, end: e})
|
|
135
|
+
start = e + 1;
|
|
136
|
+
outputLine++;
|
|
137
|
+
lineCounter = Math.max(lineCounter, outputLine)
|
|
138
|
+
lbi++;
|
|
87
139
|
}
|
|
88
|
-
|
|
89
|
-
newLines[currentLine[j][k]].staff[j].voices[k].push(element);
|
|
90
|
-
if (element.el_type === 'stem') {
|
|
91
|
-
// This is a nice trick to just pay attention to the last setting of each type.
|
|
92
|
-
voiceStart[element.el_type] = element;
|
|
93
|
-
}
|
|
140
|
+
measureNumber++;
|
|
94
141
|
|
|
95
|
-
if (element.el_type === 'bar') {
|
|
96
|
-
measureNumber[j][k]++;
|
|
97
|
-
if (lineBreaks[measureNumber[j][k]]) {
|
|
98
|
-
startNewLine[j][k] = true;
|
|
99
|
-
currentLine[j][k]++;
|
|
100
|
-
measureMarker[j][k] = element.barNumber;
|
|
101
|
-
delete element.barNumber;
|
|
102
|
-
}
|
|
103
142
|
}
|
|
104
143
|
}
|
|
105
|
-
|
|
144
|
+
lineBreakIndexes.push({ ogLine: i, line: outputLine, staff: j, voice: k, start: start, end: voice.length})
|
|
145
|
+
outputLine++;
|
|
146
|
+
lineCounter = Math.max(lineCounter, outputLine)
|
|
106
147
|
}
|
|
107
148
|
}
|
|
108
|
-
linesWithoutStaff = 0;
|
|
109
149
|
} else {
|
|
110
|
-
|
|
111
|
-
|
|
150
|
+
lineBreakIndexes.push({ ogLine: i, line: outputLine })
|
|
151
|
+
outputLine++;
|
|
152
|
+
lineCounter = Math.max(lineCounter, outputLine)
|
|
112
153
|
}
|
|
113
154
|
}
|
|
114
|
-
|
|
155
|
+
return lineBreakIndexes;
|
|
115
156
|
}
|
|
116
157
|
|
|
158
|
+
|
|
117
159
|
function freeFormLineBreaks(widths, lineBreakPoint) {
|
|
118
160
|
var lineBreaks = [];
|
|
119
161
|
var totals = [];
|
|
@@ -146,159 +188,6 @@ function freeFormLineBreaks(widths, lineBreakPoint) {
|
|
|
146
188
|
return { lineBreaks: lineBreaks, totals: totals };
|
|
147
189
|
}
|
|
148
190
|
|
|
149
|
-
// function createLineTestArray(numLines, numMeasures, maxMeasuresPerLine, minMeasuresPerLine) {
|
|
150
|
-
// var tries = [];
|
|
151
|
-
// // To get all the iterations, it is every digit in a particular base-numbering system.
|
|
152
|
-
// // That is, we want to generate every number that is (numLines-1) digits, in base (max-min+1)
|
|
153
|
-
// // For instance, for 5 lines where the min is 6 and max is 8, we want ever combination of 4 digits in base 3.
|
|
154
|
-
// var base = maxMeasuresPerLine - minMeasuresPerLine + 1;
|
|
155
|
-
// var digits = numLines - 1; // The last digit is fixed: it is what ever is needed to sum up to the total number of measures.
|
|
156
|
-
// var done = false;
|
|
157
|
-
// var iter = 0;
|
|
158
|
-
// while (!done) {
|
|
159
|
-
// var attempt = [];
|
|
160
|
-
// var num = iter;
|
|
161
|
-
// var total = 0;
|
|
162
|
-
// for (var d = digits - 1; d >= 0; d--) {
|
|
163
|
-
// attempt[d] = (num % base) + minMeasuresPerLine;
|
|
164
|
-
// num = Math.floor(num / base);
|
|
165
|
-
// total += attempt[d];
|
|
166
|
-
// }
|
|
167
|
-
// if (num > 0)
|
|
168
|
-
// done = true; // continue until we exceed the greatest number. We know because there is a remainer.
|
|
169
|
-
// else {
|
|
170
|
-
// var lastLine = numMeasures - total;
|
|
171
|
-
// if (lastLine >= minMeasuresPerLine && lastLine <= maxMeasuresPerLine) {
|
|
172
|
-
// attempt[digits] = lastLine;
|
|
173
|
-
// tries.push(attempt);
|
|
174
|
-
// }
|
|
175
|
-
// iter++;
|
|
176
|
-
// }
|
|
177
|
-
// }
|
|
178
|
-
// return tries;
|
|
179
|
-
// }
|
|
180
|
-
|
|
181
|
-
// function getVariance(attempt, idealLineBreak, widths, allowableOverage) {
|
|
182
|
-
// var measureNumber = 0;
|
|
183
|
-
// var thisWorstVariance = 0;
|
|
184
|
-
// for (var j = 0; j < attempt.length; j++) {
|
|
185
|
-
// var lineWidth = 0;
|
|
186
|
-
// var measuresThisLine = attempt[j];
|
|
187
|
-
// for (var k = 0; k < measuresThisLine; k++) {
|
|
188
|
-
// lineWidth += widths[measureNumber++];
|
|
189
|
-
// }
|
|
190
|
-
// if (lineWidth > allowableOverage)
|
|
191
|
-
// return null;
|
|
192
|
-
// var variance = Math.abs(lineWidth - idealLineBreak);
|
|
193
|
-
// if (variance > thisWorstVariance)
|
|
194
|
-
// thisWorstVariance = variance;
|
|
195
|
-
// }
|
|
196
|
-
// return thisWorstVariance;
|
|
197
|
-
// }
|
|
198
|
-
|
|
199
|
-
// function getMaxVariance(widths, lineBreakPoint, lineBreaks) {
|
|
200
|
-
// var maxVariance = 0;
|
|
201
|
-
// var numLines = lineBreaks.length + 1; // the last line doesn't have an explicit break
|
|
202
|
-
// var measureNumber = 0;
|
|
203
|
-
// var totals = [];
|
|
204
|
-
// for (var i = 0; i <= lineBreaks.length; i++) {
|
|
205
|
-
// var breakMeasure = (i === lineBreaks.length) ? widths.length : lineBreaks[i];
|
|
206
|
-
// var thisTotal = 0;
|
|
207
|
-
// for (var j = measureNumber; j < breakMeasure; j++) {
|
|
208
|
-
// thisTotal += widths[j];
|
|
209
|
-
// }
|
|
210
|
-
// measureNumber = breakMeasure;
|
|
211
|
-
// var thisVariance = thisTotal <= lineBreakPoint ? lineBreakPoint - thisTotal : 1000000;
|
|
212
|
-
// totals.push({total: thisTotal, variance: thisVariance})
|
|
213
|
-
// maxVariance = Math.max(maxVariance, thisVariance);
|
|
214
|
-
// }
|
|
215
|
-
//
|
|
216
|
-
// console.log(lineBreakPoint, totals)
|
|
217
|
-
// return maxVariance;
|
|
218
|
-
// }
|
|
219
|
-
|
|
220
|
-
function getVariance(widths, lineBreaks) {
|
|
221
|
-
var numLines = lineBreaks.length + 1; // the last line doesn't have an explicit break
|
|
222
|
-
var avg = widths.total / numLines;
|
|
223
|
-
var largestVariance = 0;
|
|
224
|
-
var measureNumber = 0;
|
|
225
|
-
for (var i = 0; i <= lineBreaks.length; i++) {
|
|
226
|
-
var breakMeasure = (i === lineBreaks.length) ? widths.measureWidths.length-1 : lineBreaks[i];
|
|
227
|
-
var thisVariance = lineVariance(widths.measureWidths, measureNumber, breakMeasure, avg);
|
|
228
|
-
measureNumber = breakMeasure+1;
|
|
229
|
-
largestVariance = Math.max(largestVariance, thisVariance);
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
return largestVariance;
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
// function getAvgVariance(widths, lineBreakPoint, lineBreaks) {
|
|
236
|
-
// var totalVariance = 0;
|
|
237
|
-
// var numLines = lineBreaks.length + 1; // the last line doesn't have an explicit break
|
|
238
|
-
// var measureNumber = 0;
|
|
239
|
-
// for (var i = 0; i <= lineBreaks.length; i++) {
|
|
240
|
-
// var breakMeasure = (i === lineBreaks.length) ? widths.length : lineBreaks[i];
|
|
241
|
-
// var thisTotal = 0;
|
|
242
|
-
// for (var j = measureNumber; j < breakMeasure; j++) {
|
|
243
|
-
// thisTotal += widths[j];
|
|
244
|
-
// }
|
|
245
|
-
// measureNumber = breakMeasure;
|
|
246
|
-
// var thisVariance = Math.abs(lineBreakPoint - thisTotal);
|
|
247
|
-
// totalVariance += thisVariance;
|
|
248
|
-
// }
|
|
249
|
-
//
|
|
250
|
-
// return totalVariance / numLines;
|
|
251
|
-
// }
|
|
252
|
-
|
|
253
|
-
function lineVariance(widths, start, end, avg) {
|
|
254
|
-
var thisTotal = lineWidth(widths, start, end);
|
|
255
|
-
var thisVariance = Math.abs(avg - thisTotal);
|
|
256
|
-
return thisVariance;
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
function lineWidth(widths, start, end) {
|
|
260
|
-
var thisTotal = 0;
|
|
261
|
-
for (var j = start; j <= end; j++)
|
|
262
|
-
thisTotal += widths[j];
|
|
263
|
-
return thisTotal;
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
// TODO-PER: For long pieces of music, this can get long, so stop finding the combinations at an arbitrary place.
|
|
267
|
-
function getAttempts(widths, start, linesLeft, min, max, lastLines) {
|
|
268
|
-
var MAX_COMBINATIONS = 1200;
|
|
269
|
-
var acc = 0;
|
|
270
|
-
var attempts = [];
|
|
271
|
-
for (var i = start; i < widths.length && acc < max; i++) {
|
|
272
|
-
acc += widths[i];
|
|
273
|
-
if (acc > max)
|
|
274
|
-
break;
|
|
275
|
-
if (acc > min) {
|
|
276
|
-
if (linesLeft > 0 && attempts.length < MAX_COMBINATIONS) {
|
|
277
|
-
var nextLines = getAttempts(widths, i + 1, linesLeft - 1, min, max, lastLines);
|
|
278
|
-
for (var j = 0; j < nextLines.length; j++)
|
|
279
|
-
attempts.push([i].concat(nextLines[j]));
|
|
280
|
-
}
|
|
281
|
-
if (linesLeft === 1 && lastLines.indexOf(i) >= 0)
|
|
282
|
-
attempts.push([i]);
|
|
283
|
-
}
|
|
284
|
-
}
|
|
285
|
-
return attempts;
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
function lastLinePossibilities(widths, start, min, max) {
|
|
289
|
-
var acc = 0;
|
|
290
|
-
var possibilities = [];
|
|
291
|
-
for (var i = widths.length-1; i >= 0; i--) {
|
|
292
|
-
acc += widths[i];
|
|
293
|
-
if (acc > max)
|
|
294
|
-
break;
|
|
295
|
-
if (acc > min && i < start) {
|
|
296
|
-
possibilities.push(i-1);
|
|
297
|
-
}
|
|
298
|
-
}
|
|
299
|
-
return possibilities;
|
|
300
|
-
}
|
|
301
|
-
|
|
302
191
|
function clone(arr) {
|
|
303
192
|
var newArr = [];
|
|
304
193
|
for (var i = 0; i < arr.length; i++)
|
|
@@ -361,8 +250,8 @@ function oneTry(measureWidths, idealWidths, accumulator, lineAccumulator, lineWi
|
|
|
361
250
|
}
|
|
362
251
|
|
|
363
252
|
function optimizeLineWidths(widths, lineBreakPoint, lineBreaks, explanation) {
|
|
364
|
-
// figure out how many lines
|
|
365
|
-
var numLines = Math.ceil(widths.total / lineBreakPoint) + 1
|
|
253
|
+
// figure out how many lines
|
|
254
|
+
var numLines = Math.ceil(widths.total / lineBreakPoint); // + 1 TODO-PER: this used to be plus one - not sure why
|
|
366
255
|
|
|
367
256
|
// get the ideal width for a line (cumulative width / num lines) - approx the same as lineBreakPoint except for rounding
|
|
368
257
|
var idealWidth = Math.floor(widths.total / numLines);
|
|
@@ -424,135 +313,6 @@ function optimizeLineWidths(widths, lineBreakPoint, lineBreaks, explanation) {
|
|
|
424
313
|
}
|
|
425
314
|
return { failed: false, lineBreaks: otherTries[smallestIndex].lineBreaks, variance: otherTries[smallestIndex].highestVariance };
|
|
426
315
|
}
|
|
427
|
-
// // Instead of having to try all the different combinations to find the best, we start with an important piece of knowledge about the lineBreaks we are given:
|
|
428
|
-
// // If there is a line too short, it is the last one.
|
|
429
|
-
// // So, let's just do a couple of tweaks to see how it works to add one or two measures to the last line.
|
|
430
|
-
// var avg = widths.total / (lineBreaks.length + 1);
|
|
431
|
-
// var variance = getVariance(widths, lineBreaks);
|
|
432
|
-
// var variancePct = variance/lineBreakPoint*100;
|
|
433
|
-
//
|
|
434
|
-
// if (lineBreaks.length === 0)
|
|
435
|
-
// return { failed: true, reason: "Only one line." };
|
|
436
|
-
//
|
|
437
|
-
// var lastLineStart = lineBreaks[lineBreaks.length-1]+1;
|
|
438
|
-
// var lastLineVariance = lineVariance(widths.measureWidths, lastLineStart, widths.measureWidths.length, avg);
|
|
439
|
-
// if (variance > lastLineVariance)
|
|
440
|
-
// return { failed: true, reason: "Last line is not too short." };
|
|
441
|
-
//
|
|
442
|
-
// // Let's get a list of all combinations that have a possibility of working. That is, all combinations where no line has a variance larger than "variance".
|
|
443
|
-
// var lastLines = lastLinePossibilities(widths.measureWidths, lastLineStart, avg - variance, avg + variance);
|
|
444
|
-
// var attempts = getAttempts(widths.measureWidths, 0, lineBreaks.length, avg - variance, avg + variance, lastLines);
|
|
445
|
-
// //console.log(attempts, avg - variance, avg + variance);
|
|
446
|
-
//
|
|
447
|
-
// var failed = true;
|
|
448
|
-
// for (var i = 0; i < attempts.length; i++) {
|
|
449
|
-
// var newVariance = getVariance(widths, attempts[i]);
|
|
450
|
-
// if (newVariance < variance) {
|
|
451
|
-
// explanation.attempts.push({
|
|
452
|
-
// type: "Optimize try", lineBreaks: attempts[i],
|
|
453
|
-
// variance: Math.round(variance), newVariance: Math.round(newVariance),
|
|
454
|
-
// totalAttempts: attempts.length
|
|
455
|
-
// });
|
|
456
|
-
// variance = newVariance;
|
|
457
|
-
// lineBreaks = attempts[i];
|
|
458
|
-
// failed = false;
|
|
459
|
-
// }
|
|
460
|
-
// }
|
|
461
|
-
// if (failed) {
|
|
462
|
-
// explanation.attempts.push({ type: "Optimize try", lineBreaks: lineBreaks, variance: variance, reason: "None of the " + attempts.length + " attempts were better." });
|
|
463
|
-
// // TODO-PER: This shouldn't be necessary, but just try to move one measure down and see if it helps.
|
|
464
|
-
// if (lineBreaks.length > 0) {
|
|
465
|
-
// var attempt = [].concat(lineBreaks);
|
|
466
|
-
// attempt[attempt.length - 1]--;
|
|
467
|
-
// newVariance = getVariance(widths, attempt);
|
|
468
|
-
// explanation.attempts.push({
|
|
469
|
-
// type: "Optimize last try", lineBreaks: attempts[i],
|
|
470
|
-
// variance: Math.round(variance), newVariance: Math.round(newVariance),
|
|
471
|
-
// totalAttempts: attempts.length
|
|
472
|
-
// });
|
|
473
|
-
// if (newVariance < variance) {
|
|
474
|
-
// variance = newVariance;
|
|
475
|
-
// lineBreaks = attempt;
|
|
476
|
-
// failed = false;
|
|
477
|
-
// }
|
|
478
|
-
// }
|
|
479
|
-
// }
|
|
480
|
-
// // Let's squeeze the line successively until it spills onto an extra line, then take the option with the lowest variance
|
|
481
|
-
// // var targetNumLines = lineBreaks.length;
|
|
482
|
-
// // var newNumLines = targetNumLines;
|
|
483
|
-
// // var TRY_INCREMENT = 1;
|
|
484
|
-
// // var tryBreakPoint = lineBreakPoint - TRY_INCREMENT;
|
|
485
|
-
// // var failed = true;
|
|
486
|
-
// // while (targetNumLines === newNumLines && tryBreakPoint > 50) {
|
|
487
|
-
// // var ff = freeFormLineBreaks(widths.measureWidths, tryBreakPoint);
|
|
488
|
-
// // newNumLines = ff.lineBreaks.length;
|
|
489
|
-
// // if (newNumLines === targetNumLines) {
|
|
490
|
-
// // var newVariance = getVariance(widths, ff.lineBreaks);
|
|
491
|
-
// // var newVariancePct = newVariance/tryBreakPoint*100;
|
|
492
|
-
// // explanation.attempts.push({type: "Optimize try", tryBreakPoint: Math.round(tryBreakPoint), lineBreaks: ff.lineBreaks, totals: ff.totals,
|
|
493
|
-
// // variance: Math.round(variance), newVariance: Math.round(newVariance), variancePct: Math.round(variancePct), newVariancePct: Math.round(newVariancePct)
|
|
494
|
-
// // });
|
|
495
|
-
// // if (newVariancePct < variancePct) {
|
|
496
|
-
// // variancePct = newVariancePct;
|
|
497
|
-
// // lineBreaks = ff.lineBreaks;
|
|
498
|
-
// // failed = false;
|
|
499
|
-
// // }
|
|
500
|
-
// // } else {
|
|
501
|
-
// // explanation.attempts.push({type: "Optimize try", explanation: "Exceeded number of lines." , tryBreakPoint: Math.round(tryBreakPoint), lineBreaks: ff.lineBreaks, totals: ff.totals, variance: variance, avg: avg, variancePct: variancePct});
|
|
502
|
-
// // }
|
|
503
|
-
// // tryBreakPoint -= TRY_INCREMENT;
|
|
504
|
-
// // }
|
|
505
|
-
//
|
|
506
|
-
// return { failed: failed, lineBreaks: lineBreaks, variance: variance };
|
|
507
|
-
// }
|
|
508
|
-
|
|
509
|
-
// function fixedNumLinesBreaks(widths, numLines, allowOver, allowableVariance) {
|
|
510
|
-
// var idealLineBreak = widths.total / numLines;
|
|
511
|
-
// // If all the measures had the same amount of stuff, then the ave would be correct.
|
|
512
|
-
// // We will test all the combinations from one less to one more than the average.
|
|
513
|
-
// var averageMeasuresPerLine = Math.round(widths.measureWidths.length / numLines);
|
|
514
|
-
// var minMeasuresPerLine = Math.max(averageMeasuresPerLine - 1, 1);
|
|
515
|
-
// var maxMeasuresPerLine = averageMeasuresPerLine + 1;
|
|
516
|
-
// var tries = createLineTestArray(numLines, widths.measureWidths.length, maxMeasuresPerLine, minMeasuresPerLine);
|
|
517
|
-
// console.log("fixedNumLinesBreaks tests ("+minMeasuresPerLine+'-'+maxMeasuresPerLine+")", numLines, tries.length)
|
|
518
|
-
//
|
|
519
|
-
// // For each possible number of measures per line, see which has the closest spacing to the ideal.
|
|
520
|
-
// var bestCase = -1;
|
|
521
|
-
// var bestCaseVariance = 1000000;
|
|
522
|
-
// for (var i = 0 ; i < tries.length; i++) {
|
|
523
|
-
// var attempt = tries[i];
|
|
524
|
-
// var variance = getVariance(attempt, idealLineBreak, widths.measureWidths, allowOver ? allowableVariance : 0);
|
|
525
|
-
// if (variance !== null) {
|
|
526
|
-
// if (variance < bestCaseVariance) {
|
|
527
|
-
// bestCaseVariance = variance;
|
|
528
|
-
// bestCase = i;
|
|
529
|
-
// }
|
|
530
|
-
// }
|
|
531
|
-
// }
|
|
532
|
-
// var failed = true;
|
|
533
|
-
// // For debugging, recreate the line widths
|
|
534
|
-
// var totals = [];
|
|
535
|
-
// if (bestCase >= 0) {
|
|
536
|
-
// failed = false;
|
|
537
|
-
// var index = 0;
|
|
538
|
-
// for (i = 0; i < tries[bestCase].length; i++) {
|
|
539
|
-
// var total = 0;
|
|
540
|
-
// for (var j = 0; j < tries[bestCase][i]; j++) {
|
|
541
|
-
// total += widths.measureWidths[index++];
|
|
542
|
-
// }
|
|
543
|
-
// totals.push(Math.round(total));
|
|
544
|
-
// }
|
|
545
|
-
// // We now have an array that contains the number of measures per line, but we want to return the absolute measure number to break on.
|
|
546
|
-
// if (tries[bestCase].length > 0) {
|
|
547
|
-
// tries[bestCase][0]--; // The results should contain the last measure number on the line, zero-based.
|
|
548
|
-
// for (i = 1; i < tries[bestCase].length; i++)
|
|
549
|
-
// tries[bestCase][i] += tries[bestCase][i - 1]; // This sets the zero-based measure number
|
|
550
|
-
// // The last line is implied and we don't need to return it
|
|
551
|
-
// tries[bestCase].pop();
|
|
552
|
-
// }
|
|
553
|
-
// }
|
|
554
|
-
// return { failed: failed, lineBreaks: tries[bestCase], bestCaseVariance: Math.round(bestCaseVariance), totals: totals };
|
|
555
|
-
// }
|
|
556
316
|
|
|
557
317
|
function fixedMeasureLineBreaks(widths, lineBreakPoint, preferredMeasuresPerLine) {
|
|
558
318
|
var lineBreaks = [];
|
|
@@ -574,8 +334,8 @@ function fixedMeasureLineBreaks(widths, lineBreakPoint, preferredMeasuresPerLine
|
|
|
574
334
|
return { failed: failed, totals: totals, lineBreaks: lineBreaks };
|
|
575
335
|
}
|
|
576
336
|
|
|
577
|
-
function
|
|
578
|
-
|
|
337
|
+
function getRevisedTuneParams(lineBreaks, staffWidth, params) {
|
|
338
|
+
|
|
579
339
|
var revisedParams = {
|
|
580
340
|
lineBreaks: lineBreaks,
|
|
581
341
|
staffwidth: staffWidth
|
|
@@ -586,21 +346,21 @@ function getRevisedTune(lineBreaks, staffWidth, abcString, params, Parse) {
|
|
|
586
346
|
}
|
|
587
347
|
}
|
|
588
348
|
|
|
589
|
-
|
|
590
|
-
return { tune: abcParser.getTune(), revisedParams: revisedParams };
|
|
349
|
+
return { revisedParams: revisedParams };
|
|
591
350
|
}
|
|
592
351
|
|
|
593
|
-
function calcLineWraps(tune, widths,
|
|
352
|
+
function calcLineWraps(tune, widths, params) {
|
|
594
353
|
// For calculating how much can go on the line, it depends on the width of the line. It is a convenience to just divide it here
|
|
595
354
|
// by the minimum spacing instead of multiplying the min spacing later.
|
|
596
355
|
// The scaling works differently: this is done by changing the scaling of the outer SVG, so the scaling needs to be compensated
|
|
597
356
|
// for here, because the actual width will be different from the calculated numbers.
|
|
598
357
|
|
|
599
358
|
// If the desired width is less than the margin, just punt and return the original tune
|
|
600
|
-
|
|
359
|
+
//console.log(widths)
|
|
360
|
+
if (widths.length === 0 || params.staffwidth < widths[0].left) {
|
|
601
361
|
return {
|
|
602
|
-
|
|
603
|
-
|
|
362
|
+
reParse: false,
|
|
363
|
+
explanation: "Staff width is narrower than the margin",
|
|
604
364
|
revisedParams: params
|
|
605
365
|
};
|
|
606
366
|
}
|
|
@@ -610,80 +370,72 @@ function calcLineWraps(tune, widths, abcString, params, Parse, engraver_controll
|
|
|
610
370
|
var maxSpacing = params.wrap.maxSpacing ? Math.max(parseFloat(params.wrap.maxSpacing), 1) : undefined;
|
|
611
371
|
if (params.wrap.lastLineLimit && !maxSpacing)
|
|
612
372
|
maxSpacing = Math.max(parseFloat(params.wrap.lastLineLimit), 1);
|
|
613
|
-
var targetHeight = params.wrap.targetHeight ? Math.max(parseInt(params.wrap.targetHeight, 10), 100) : undefined;
|
|
614
|
-
var preferredMeasuresPerLine = params.wrap.preferredMeasuresPerLine ? Math.max(parseInt(params.wrap.preferredMeasuresPerLine, 10),
|
|
615
|
-
|
|
616
|
-
var
|
|
617
|
-
var
|
|
618
|
-
var
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
var
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
373
|
+
// var targetHeight = params.wrap.targetHeight ? Math.max(parseInt(params.wrap.targetHeight, 10), 100) : undefined;
|
|
374
|
+
var preferredMeasuresPerLine = params.wrap.preferredMeasuresPerLine ? Math.max(parseInt(params.wrap.preferredMeasuresPerLine, 10), 0) : undefined;
|
|
375
|
+
|
|
376
|
+
var accumulatedLineBreaks = [];
|
|
377
|
+
var explanations = [];
|
|
378
|
+
for (var s = 0; s < widths.length; s++) {
|
|
379
|
+
var section = widths[s];
|
|
380
|
+
var usableWidth = params.staffwidth - section.left;
|
|
381
|
+
var lineBreakPoint = usableWidth / minSpacing / scale;
|
|
382
|
+
var minLineSize = usableWidth / maxSpacing / scale;
|
|
383
|
+
var allowableVariance = usableWidth / minSpacingLimit / scale;
|
|
384
|
+
var explanation = {
|
|
385
|
+
widths: section,
|
|
386
|
+
lineBreakPoint: lineBreakPoint,
|
|
387
|
+
minLineSize: minLineSize,
|
|
388
|
+
attempts: [],
|
|
389
|
+
staffWidth: params.staffwidth,
|
|
390
|
+
minWidth: Math.round(allowableVariance)
|
|
391
|
+
};
|
|
629
392
|
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
393
|
+
// If there is a preferred number of measures per line, test that first. If none of the lines is too long, then we're finished.
|
|
394
|
+
var lineBreaks = null;
|
|
395
|
+
if (preferredMeasuresPerLine) {
|
|
396
|
+
var f = fixedMeasureLineBreaks(section.measureWidths, lineBreakPoint, preferredMeasuresPerLine);
|
|
397
|
+
explanation.attempts.push({
|
|
398
|
+
type: "Fixed Measures Per Line",
|
|
399
|
+
preferredMeasuresPerLine: preferredMeasuresPerLine,
|
|
400
|
+
lineBreaks: f.lineBreaks,
|
|
401
|
+
failed: f.failed,
|
|
402
|
+
totals: f.totals
|
|
403
|
+
});
|
|
404
|
+
if (!f.failed)
|
|
405
|
+
lineBreaks = f.lineBreaks;
|
|
406
|
+
}
|
|
636
407
|
|
|
637
|
-
//
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
408
|
+
// If we don't have lineBreaks yet, use the free form method of line breaks.
|
|
409
|
+
// This will be called either if Preferred Measures is not used, or if the music is just weird - like a single measure is way too crowded.
|
|
410
|
+
if (!lineBreaks) {
|
|
411
|
+
var ff = freeFormLineBreaks(section.measureWidths, lineBreakPoint);
|
|
412
|
+
explanation.attempts.push({type: "Free Form", lineBreaks: ff.lineBreaks, totals: ff.totals});
|
|
641
413
|
lineBreaks = ff.lineBreaks;
|
|
642
|
-
}
|
|
643
414
|
|
|
415
|
+
// We now have an acceptable number of lines, but the measures may not be optimally distributed. See if there is a better distribution.
|
|
416
|
+
if (lineBreaks.length > 0 && section.measureWidths.length < 25) {
|
|
417
|
+
// Only do this if everything doesn't fit on one line.
|
|
418
|
+
// This is an intensive operation and it is optional so just do it for shorter music.
|
|
419
|
+
ff = optimizeLineWidths(section, lineBreakPoint, lineBreaks, explanation);
|
|
420
|
+
explanation.attempts.push({
|
|
421
|
+
type: "Optimize",
|
|
422
|
+
failed: ff.failed,
|
|
423
|
+
reason: ff.reason,
|
|
424
|
+
lineBreaks: ff.lineBreaks,
|
|
425
|
+
totals: ff.totals
|
|
426
|
+
});
|
|
427
|
+
if (!ff.failed)
|
|
428
|
+
lineBreaks = ff.lineBreaks;
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
accumulatedLineBreaks.push(lineBreaks);
|
|
432
|
+
explanations.push(explanation);
|
|
433
|
+
}
|
|
644
434
|
// If the vertical space exceeds targetHeight, remove a line and try again. If that is too crowded, then don't use it.
|
|
645
435
|
var staffWidth = params.staffwidth;
|
|
646
|
-
var ret =
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
explanation.attempts.push({type: "heightCheck", height: newWidths.height });
|
|
650
|
-
|
|
651
|
-
// if all of the lines are too sparse, make the width narrower.
|
|
652
|
-
// TODO-PER: implement this case.
|
|
653
|
-
|
|
654
|
-
// If one line and the spacing is > maxSpacing, make the width narrower.
|
|
655
|
-
if (lineBreaks.length === 0 && minLineSize > widths.total) {
|
|
656
|
-
staffWidth = (widths.total * maxSpacing * scale) + widths.left;
|
|
657
|
-
explanation.attempts.push({type: "too sparse", newWidth: Math.round(staffWidth)})
|
|
658
|
-
gotTune = false;
|
|
659
|
-
}
|
|
660
|
-
|
|
661
|
-
// if (ret.lineBreaks.length === 0) {
|
|
662
|
-
// // Everything fits on one line, so see if there is TOO much space and the staff width needs to be shortened.
|
|
663
|
-
// if (minLineSize > 0 && ret.totalThisLine > 0 && ret.totalThisLine < minLineSize)
|
|
664
|
-
// staffWidth = staffWidth / (minLineSize / ret.totalThisLine);
|
|
665
|
-
// } else if (ret.totalThisLine < minLineSize) {
|
|
666
|
-
// // the last line is too short, so attempt to redistribute by changing the min.
|
|
667
|
-
// // We will try more and less space alternatively. The space can't be less than 1.0, and we'll try in 0.1 increments.
|
|
668
|
-
// var minTrys = [];
|
|
669
|
-
// if (minSpacing > 1.1)
|
|
670
|
-
// minTrys.push(minSpacing - 0.1);
|
|
671
|
-
// minTrys.push(minSpacing + 0.1);
|
|
672
|
-
// if (minSpacing > 1.2)
|
|
673
|
-
// minTrys.push(minSpacing - 0.2);
|
|
674
|
-
// minTrys.push(minSpacing + 0.2);
|
|
675
|
-
// if (minSpacing > 1.3)
|
|
676
|
-
// minTrys.push(minSpacing - 0.3);
|
|
677
|
-
// minTrys.push(minSpacing + 0.3);
|
|
678
|
-
// for (var i = 0; i < minTrys.length && ret.totalThisLine < minLineSize; i++) {
|
|
679
|
-
// lineBreakPoint = (params.staffwidth - widths.left) / minTrys[i] / scale;
|
|
680
|
-
// ret = calcLineBreaks(widths.measureWidths, lineBreakPoint);
|
|
681
|
-
// }
|
|
682
|
-
// }
|
|
683
|
-
|
|
684
|
-
if (!gotTune)
|
|
685
|
-
ret = getRevisedTune(lineBreaks, staffWidth, abcString, params, Parse);
|
|
686
|
-
ret.explanation = explanation;
|
|
436
|
+
var ret = getRevisedTuneParams(accumulatedLineBreaks, staffWidth, params);
|
|
437
|
+
ret.explanation = explanations;
|
|
438
|
+
ret.reParse = true;
|
|
687
439
|
return ret;
|
|
688
440
|
}
|
|
689
441
|
|