@goplayerjuggler/abc-tools 1.0.0 → 1.0.2
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/package.json +3 -2
- package/src/incipit.js +268 -0
- package/src/index.js +5 -1
- package/src/manipulator.js +0 -31
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@goplayerjuggler/abc-tools",
|
|
3
|
-
"version": "1.0.
|
|
4
|
-
"description": "sorting algorithm and implementation for ABC tunes; plus other tools
|
|
3
|
+
"version": "1.0.2",
|
|
4
|
+
"description": "sorting algorithm and implementation for ABC tunes; plus other tools for parsing and manipulating ABC tunes",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"scripts": {
|
|
7
7
|
"test": "jest",
|
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
"music",
|
|
16
16
|
"melody",
|
|
17
17
|
"sorting",
|
|
18
|
+
"parsing",
|
|
18
19
|
"modal",
|
|
19
20
|
"tune",
|
|
20
21
|
"traditional",
|
package/src/incipit.js
ADDED
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
const { Fraction } = require("./math.js");
|
|
3
|
+
const {getFirstBars} = require("./manipulator.js")
|
|
4
|
+
|
|
5
|
+
const {
|
|
6
|
+
getUnitLength,
|
|
7
|
+
getMeter
|
|
8
|
+
} = require("./parser.js");
|
|
9
|
+
|
|
10
|
+
//const incipitLength = 35;
|
|
11
|
+
//
|
|
12
|
+
// Clean an incipit line
|
|
13
|
+
//
|
|
14
|
+
// function cleanIncipitLine(theTextIncipit) {
|
|
15
|
+
// //console.log("Starting incipit:");
|
|
16
|
+
// //console.log(theTextIncipit);
|
|
17
|
+
|
|
18
|
+
// // Strip any embedded voice [V:*]
|
|
19
|
+
// let searchRegExp = /\[V:\s*\d+\]/gm;
|
|
20
|
+
// theTextIncipit = theTextIncipit.replace(searchRegExp, "");
|
|
21
|
+
// //console.log(theTextIncipit);
|
|
22
|
+
|
|
23
|
+
// // Strip any embedded voice V: *
|
|
24
|
+
// //searchRegExp = /V: [^ ]+ /gm
|
|
25
|
+
// searchRegExp = /V:\s+\S+\s/gm;
|
|
26
|
+
// theTextIncipit = theTextIncipit.replace(searchRegExp, "");
|
|
27
|
+
// //console.log(theTextIncipit);
|
|
28
|
+
|
|
29
|
+
// // Strip any embedded voice V:*
|
|
30
|
+
// searchRegExp = /V:[^ ]+ /gm;
|
|
31
|
+
// theTextIncipit = theTextIncipit.replace(searchRegExp, "");
|
|
32
|
+
// //console.log(theTextIncipit);
|
|
33
|
+
|
|
34
|
+
// // Sanitize !*! style annotations, but keep !fermata!
|
|
35
|
+
// searchRegExp = /!(?!fermata!)[^!\n]*!/gm;
|
|
36
|
+
// theTextIncipit = theTextIncipit.replace(searchRegExp, "");
|
|
37
|
+
// //console.log(theTextIncipit);
|
|
38
|
+
|
|
39
|
+
// // Strip out repeat marks
|
|
40
|
+
// theTextIncipit = theTextIncipit.replaceAll("|:", "|");
|
|
41
|
+
// theTextIncipit = theTextIncipit.replaceAll(":|", "|");
|
|
42
|
+
|
|
43
|
+
// // strip out 1st 2nd etc time repeats
|
|
44
|
+
// searchRegExp = /\[\d(,\d)*/gm;
|
|
45
|
+
// theTextIncipit = theTextIncipit.replace(searchRegExp, "");
|
|
46
|
+
|
|
47
|
+
// //console.log(theTextIncipit);
|
|
48
|
+
|
|
49
|
+
// // Strip out brackets
|
|
50
|
+
// // theTextIncipit = theTextIncipit.replaceAll("[", "");
|
|
51
|
+
// //console.log(theTextIncipit);
|
|
52
|
+
|
|
53
|
+
// // Strip out brackets
|
|
54
|
+
// // theTextIncipit = theTextIncipit.replaceAll("]", "");
|
|
55
|
+
// //console.log(theTextIncipit);
|
|
56
|
+
|
|
57
|
+
// // // Strip out continuations
|
|
58
|
+
// // theTextIncipit = theTextIncipit.replaceAll("\\", "");
|
|
59
|
+
|
|
60
|
+
// // Segno
|
|
61
|
+
// theTextIncipit = theTextIncipit.replaceAll("S", "");
|
|
62
|
+
|
|
63
|
+
// // Strip out comments
|
|
64
|
+
// theTextIncipit = theTextIncipit.replace(/"[^"]+"/gm, "");
|
|
65
|
+
// // Strip out inline parts
|
|
66
|
+
// theTextIncipit = theTextIncipit.replace(/\[P:[Ⅰ\w]\]/gm, "");
|
|
67
|
+
|
|
68
|
+
// //console.log("Final raw incipit :");
|
|
69
|
+
// //console.log(theTextIncipit);
|
|
70
|
+
|
|
71
|
+
// return theTextIncipit;
|
|
72
|
+
// }
|
|
73
|
+
|
|
74
|
+
function StripAnnotationsOneForIncipits(theNotes) {
|
|
75
|
+
// Strip out tempo markings
|
|
76
|
+
let searchRegExp = /^Q:.*[\r\n]*/gm;
|
|
77
|
+
|
|
78
|
+
// Strip out tempo markings
|
|
79
|
+
theNotes = theNotes.replace(searchRegExp, "");
|
|
80
|
+
|
|
81
|
+
// Strip out Z: annotation
|
|
82
|
+
searchRegExp = /^Z:.*[\r\n]*/gm;
|
|
83
|
+
|
|
84
|
+
// Strip out Z: annotation
|
|
85
|
+
theNotes = theNotes.replace(searchRegExp, "");
|
|
86
|
+
|
|
87
|
+
// Strip out R: annotation
|
|
88
|
+
searchRegExp = /^R:.*[\r\n]*/gm;
|
|
89
|
+
|
|
90
|
+
// Strip out R: annotation
|
|
91
|
+
theNotes = theNotes.replace(searchRegExp, "");
|
|
92
|
+
|
|
93
|
+
// Strip out S: annotation
|
|
94
|
+
searchRegExp = /^S:.*[\r\n]*/gm;
|
|
95
|
+
|
|
96
|
+
// Strip out S: annotation
|
|
97
|
+
theNotes = theNotes.replace(searchRegExp, "");
|
|
98
|
+
|
|
99
|
+
// Strip out N: annotation
|
|
100
|
+
searchRegExp = /^N:.*[\r\n]*/gm;
|
|
101
|
+
|
|
102
|
+
// Strip out N: annotation
|
|
103
|
+
theNotes = theNotes.replace(searchRegExp, "");
|
|
104
|
+
|
|
105
|
+
// Strip out D: annotation
|
|
106
|
+
searchRegExp = /^D:.*[\r\n]*/gm;
|
|
107
|
+
|
|
108
|
+
// Strip out D: annotation
|
|
109
|
+
theNotes = theNotes.replace(searchRegExp, "");
|
|
110
|
+
|
|
111
|
+
// Strip out H: annotation
|
|
112
|
+
searchRegExp = /^H:.*[\r\n]*/gm;
|
|
113
|
+
|
|
114
|
+
// Strip out H: annotation
|
|
115
|
+
theNotes = theNotes.replace(searchRegExp, "");
|
|
116
|
+
|
|
117
|
+
// Strip out B: annotation
|
|
118
|
+
searchRegExp = /^B:.*[\r\n]*/gm;
|
|
119
|
+
|
|
120
|
+
// Strip out B: annotation
|
|
121
|
+
theNotes = theNotes.replace(searchRegExp, "");
|
|
122
|
+
|
|
123
|
+
// Strip out C: annotation
|
|
124
|
+
searchRegExp = /^C:.*[\r\n]*/gm;
|
|
125
|
+
|
|
126
|
+
// Strip out C: annotation
|
|
127
|
+
theNotes = theNotes.replace(searchRegExp, "");
|
|
128
|
+
|
|
129
|
+
// Strip out O: annotation
|
|
130
|
+
searchRegExp = /^O:.*[\r\n]*/gm;
|
|
131
|
+
|
|
132
|
+
// Strip out O: annotation
|
|
133
|
+
theNotes = theNotes.replace(searchRegExp, "");
|
|
134
|
+
|
|
135
|
+
// Strip out A: annotation
|
|
136
|
+
searchRegExp = /^A:.*[\r\n]*/gm;
|
|
137
|
+
|
|
138
|
+
// Strip out A: annotation
|
|
139
|
+
theNotes = theNotes.replace(searchRegExp, "");
|
|
140
|
+
|
|
141
|
+
// Strip out P: annotation
|
|
142
|
+
searchRegExp = /^P:.*[\r\n]*/gm;
|
|
143
|
+
|
|
144
|
+
// Strip out P: annotation
|
|
145
|
+
theNotes = theNotes.replace(searchRegExp, "");
|
|
146
|
+
|
|
147
|
+
return theNotes;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
//
|
|
151
|
+
// Strip all the text annotations in the ABC
|
|
152
|
+
//
|
|
153
|
+
function StripTextAnnotationsOne(theNotes) {
|
|
154
|
+
// Strip out text markings
|
|
155
|
+
let searchRegExp = /%%text .*[\r\n]*/gm;
|
|
156
|
+
|
|
157
|
+
theNotes = theNotes.replace(searchRegExp, "");
|
|
158
|
+
|
|
159
|
+
searchRegExp = /%%text[\r\n]/gm;
|
|
160
|
+
|
|
161
|
+
theNotes = theNotes.replace(searchRegExp, "");
|
|
162
|
+
|
|
163
|
+
// Strip out %%center annotation
|
|
164
|
+
searchRegExp = /%%center.*[\r\n]*/gm;
|
|
165
|
+
|
|
166
|
+
// Strip out %%center annotation
|
|
167
|
+
theNotes = theNotes.replace(searchRegExp, "");
|
|
168
|
+
|
|
169
|
+
// Strip out %%right annotation
|
|
170
|
+
searchRegExp = /%%right.*[\r\n]*/gm;
|
|
171
|
+
|
|
172
|
+
// Strip out %%right annotation
|
|
173
|
+
theNotes = theNotes.replace(searchRegExp, "");
|
|
174
|
+
|
|
175
|
+
// Strip out %%begintext / %%endtext blocks
|
|
176
|
+
theNotes = theNotes.replace(/^%%begintext[\s\S]*?^%%endtext.*(\r?\n)?/gm, "");
|
|
177
|
+
|
|
178
|
+
return theNotes;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
//
|
|
182
|
+
// Strip all the chords in the ABC
|
|
183
|
+
//
|
|
184
|
+
function StripChordsOne(theNotes) {
|
|
185
|
+
function match_callback(match) {
|
|
186
|
+
// Don't strip tab annotations, only chords
|
|
187
|
+
if (match.indexOf('"_') === -1 && match.indexOf('"^') === -1) {
|
|
188
|
+
// Try and avoid stripping long text strings that aren't chords
|
|
189
|
+
if (match.length > 9) {
|
|
190
|
+
return match;
|
|
191
|
+
}
|
|
192
|
+
// If there are spaces in the match, also probably not a chord
|
|
193
|
+
else if (match.indexOf(" ") !== -1) {
|
|
194
|
+
return match;
|
|
195
|
+
} else {
|
|
196
|
+
return "";
|
|
197
|
+
}
|
|
198
|
+
} else {
|
|
199
|
+
return match;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// Strip out chord markings and not text annotations
|
|
204
|
+
const searchRegExp = /"[^"]*"/gm;
|
|
205
|
+
|
|
206
|
+
const output = theNotes
|
|
207
|
+
.split("\n")
|
|
208
|
+
.map((line) => {
|
|
209
|
+
// If line starts with one of the forbidden prefixes, skip replacement
|
|
210
|
+
if (/^[XTMKLQWZRCAOPNGHBDFSIV]:/.test(line) || /^%/.test(line)) {
|
|
211
|
+
return line;
|
|
212
|
+
} else {
|
|
213
|
+
return line.replace(searchRegExp, match_callback);
|
|
214
|
+
}
|
|
215
|
+
})
|
|
216
|
+
.join("\n");
|
|
217
|
+
|
|
218
|
+
// Replace the ABC
|
|
219
|
+
return output;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
function sanitise (theTune) {
|
|
223
|
+
|
|
224
|
+
// Strip out annotations
|
|
225
|
+
theTune = StripAnnotationsOneForIncipits(theTune);
|
|
226
|
+
|
|
227
|
+
// Strip out textnnotations
|
|
228
|
+
theTune = StripTextAnnotationsOne(theTune);
|
|
229
|
+
|
|
230
|
+
// Strip out chord markings
|
|
231
|
+
theTune = StripChordsOne(theTune);
|
|
232
|
+
|
|
233
|
+
return theTune;
|
|
234
|
+
};
|
|
235
|
+
|
|
236
|
+
|
|
237
|
+
/**
|
|
238
|
+
* Get incipit (opening bars) of a tune for display/search purposes
|
|
239
|
+
* @param {object} Object of the form {abc} with optional property: numBars
|
|
240
|
+
* @param {string} params.abc - ABC notation
|
|
241
|
+
* @param {number|Fraction} params.numBars - Number of bars to return, counting the anacrucis if there is one. (default:2)
|
|
242
|
+
* @returns {string} - ABC incipit
|
|
243
|
+
*/
|
|
244
|
+
function getIncipit({
|
|
245
|
+
abc,
|
|
246
|
+
numBars, //, part=null
|
|
247
|
+
} = {}) {
|
|
248
|
+
if (!numBars) {
|
|
249
|
+
numBars = 2;
|
|
250
|
+
const currentMeter = getMeter(abc);
|
|
251
|
+
const unitLength = getUnitLength(abc);
|
|
252
|
+
if (
|
|
253
|
+
(currentMeter[0] === 4 &&
|
|
254
|
+
currentMeter[1] === 4 &&
|
|
255
|
+
unitLength.den === 16) ||
|
|
256
|
+
(currentMeter[0] === 4 &&
|
|
257
|
+
currentMeter[1] === 2 &&
|
|
258
|
+
unitLength.den === 8) ||
|
|
259
|
+
(currentMeter[0] === 12 && currentMeter[1] === 8)
|
|
260
|
+
) {
|
|
261
|
+
numBars = new Fraction(3, 2);
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
abc = sanitise(abc)
|
|
265
|
+
return getFirstBars(abc, numBars, true, true, { all: true });
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
module.exports = {getIncipit}
|
package/src/index.js
CHANGED
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
const parser = require('./parser.js');
|
|
7
7
|
const manipulator = require('./manipulator.js');
|
|
8
8
|
const sort = require('./contour-sort.js');
|
|
9
|
+
const incipit = require('./incipit.js');
|
|
9
10
|
|
|
10
11
|
module.exports = {
|
|
11
12
|
// Parser functions
|
|
@@ -15,5 +16,8 @@ module.exports = {
|
|
|
15
16
|
...manipulator,
|
|
16
17
|
|
|
17
18
|
// Sort functions
|
|
18
|
-
...sort
|
|
19
|
+
...sort,
|
|
20
|
+
|
|
21
|
+
// Incipit functions
|
|
22
|
+
...incipit
|
|
19
23
|
};
|
package/src/manipulator.js
CHANGED
|
@@ -2,7 +2,6 @@ const { Fraction } = require("./math.js");
|
|
|
2
2
|
const {
|
|
3
3
|
parseABCWithBars,
|
|
4
4
|
getMeter,
|
|
5
|
-
getUnitLength,
|
|
6
5
|
calculateBarDurations,
|
|
7
6
|
} = require("./parser.js");
|
|
8
7
|
|
|
@@ -439,39 +438,9 @@ function getFirstBars(
|
|
|
439
438
|
)}`;
|
|
440
439
|
}
|
|
441
440
|
|
|
442
|
-
/**
|
|
443
|
-
* Get incipit (opening bars) of a tune for display/search purposes
|
|
444
|
-
* @param {object} Object of the form {abc} with optional property: numBars
|
|
445
|
-
* @param {string} params.abc - ABC notation
|
|
446
|
-
* @param {number|Fraction} params.numBars - Number of bars to return, counting the anacrucis if there is one. (default:2)
|
|
447
|
-
* @returns {string} - ABC incipit
|
|
448
|
-
*/
|
|
449
|
-
function getIncipit({
|
|
450
|
-
abc,
|
|
451
|
-
numBars, //, part=null
|
|
452
|
-
} = {}) {
|
|
453
|
-
if (!numBars) {
|
|
454
|
-
numBars = 2;
|
|
455
|
-
const currentMeter = getMeter(abc);
|
|
456
|
-
const unitLength = getUnitLength(abc);
|
|
457
|
-
if (
|
|
458
|
-
(currentMeter[0] === 4 &&
|
|
459
|
-
currentMeter[1] === 4 &&
|
|
460
|
-
unitLength.den === 16) ||
|
|
461
|
-
(currentMeter[0] === 4 &&
|
|
462
|
-
currentMeter[1] === 2 &&
|
|
463
|
-
unitLength.den === 8) ||
|
|
464
|
-
(currentMeter[0] === 12 && currentMeter[1] === 8)
|
|
465
|
-
) {
|
|
466
|
-
numBars = new Fraction(3, 2);
|
|
467
|
-
}
|
|
468
|
-
}
|
|
469
|
-
return getFirstBars(abc, numBars, true, true, { all: true });
|
|
470
|
-
}
|
|
471
441
|
|
|
472
442
|
module.exports = {
|
|
473
443
|
getFirstBars,
|
|
474
|
-
getIncipit,
|
|
475
444
|
hasAnacrucis,
|
|
476
445
|
toggleMeter_4_4_to_4_2,
|
|
477
446
|
toggleMeter_6_8_to_12_8,
|