@hymnbook/abc 0.0.1 → 0.2.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/dist/{index.mjs → index.cjs} +206 -44
- package/dist/{index.d.mts → index.d.cts} +67 -9
- package/dist/index.d.ts +67 -9
- package/dist/index.js +157 -92
- package/package.json +18 -2
- package/src/based.ts +11 -3
- package/src/deparser.ts +186 -0
- package/src/index.ts +4 -3
- package/src/{abc.ts → parser.ts} +54 -41
- package/src/{abcTypes.ts → types.ts} +6 -3
package/src/{abc.ts → parser.ts}
RENAMED
|
@@ -8,13 +8,20 @@ import {
|
|
|
8
8
|
TuneObject,
|
|
9
9
|
VoiceItem,
|
|
10
10
|
VoiceItemNote
|
|
11
|
-
} from "./
|
|
11
|
+
} from "./types";
|
|
12
12
|
import { validate } from "./validation";
|
|
13
|
+
import { addInfoFieldsToMelody } from "./deparser";
|
|
13
14
|
|
|
14
15
|
// See also https://abcnotation.com/examples
|
|
15
16
|
|
|
16
|
-
|
|
17
|
-
|
|
17
|
+
/**
|
|
18
|
+
* Generates an AbcSong object from an ABC notation string.
|
|
19
|
+
* This function does some extra processing to handle slurs and lyrics properly.
|
|
20
|
+
* If you do not want this, use `convertStringToAbcTune` directly.
|
|
21
|
+
*
|
|
22
|
+
* @param abc
|
|
23
|
+
*/
|
|
24
|
+
export const parse = (abc: string): AbcSong => {
|
|
18
25
|
// Remove comments
|
|
19
26
|
abc = abc
|
|
20
27
|
.replace(/%.*/g, "")
|
|
@@ -24,9 +31,6 @@ export const parse = (abc: string): AbcSong | undefined => {
|
|
|
24
31
|
extractInfoFields(abc, song);
|
|
25
32
|
|
|
26
33
|
const tuneObject = convertStringToAbcTune(abc);
|
|
27
|
-
if (tuneObject === undefined) {
|
|
28
|
-
return undefined;
|
|
29
|
-
}
|
|
30
34
|
|
|
31
35
|
// Get the first staff only (thus in case of multiple instrument play, only take the first instrument)
|
|
32
36
|
song.clef = tuneObject.lines!![0].staff!![0].clef || song.clef;
|
|
@@ -118,6 +122,12 @@ const processSlursForLine = (line: VoiceItem[]) => {
|
|
|
118
122
|
});
|
|
119
123
|
};
|
|
120
124
|
|
|
125
|
+
/**
|
|
126
|
+
* Get an info/header field from an ABC notation string.
|
|
127
|
+
* @param abc
|
|
128
|
+
* @param field
|
|
129
|
+
* @param _default
|
|
130
|
+
*/
|
|
121
131
|
export const getField = (abc: string, field: string, _default?: string): (string | undefined) => {
|
|
122
132
|
const result = abc.match(new RegExp("(^|\n) *\t*" + field + ":(.*)?"));
|
|
123
133
|
if (result == null || result.length !== 3 || result[2] == null) {
|
|
@@ -126,6 +136,11 @@ export const getField = (abc: string, field: string, _default?: string): (string
|
|
|
126
136
|
return result[2].trim();
|
|
127
137
|
};
|
|
128
138
|
|
|
139
|
+
/**
|
|
140
|
+
* Extract info/header fields from an ABC notation string into an AbcSong object and return the remaining melody string.
|
|
141
|
+
* @param abc
|
|
142
|
+
* @param song
|
|
143
|
+
*/
|
|
129
144
|
export const extractInfoFields = (abc: string, song: AbcSong): string => {
|
|
130
145
|
song.area = getField(abc, "A");
|
|
131
146
|
song.book = getField(abc, "B");
|
|
@@ -152,6 +167,7 @@ export const extractInfoFields = (abc: string, song: AbcSong): string => {
|
|
|
152
167
|
song.voice = getField(abc, "V");
|
|
153
168
|
song.referenceNumber = getField(abc, "X", "1");
|
|
154
169
|
song.transcription = getField(abc, "Z");
|
|
170
|
+
|
|
155
171
|
return abc
|
|
156
172
|
.replace(/%.*\n/g, "")
|
|
157
173
|
.replace(/(^|\n) *\t*[ABCDFGHIKLMmNOPQRrSsTUVXZ]:.*/g, "")
|
|
@@ -160,7 +176,12 @@ export const extractInfoFields = (abc: string, song: AbcSong): string => {
|
|
|
160
176
|
.replace(/\n*$/g, "");
|
|
161
177
|
};
|
|
162
178
|
|
|
163
|
-
|
|
179
|
+
/**
|
|
180
|
+
* Extract notes and lyrics from an ABC notation string as a single line for each.
|
|
181
|
+
* Note that you must first remove info/header fields before using this function.
|
|
182
|
+
* @param abc
|
|
183
|
+
*/
|
|
184
|
+
export const squashNotesAndLyrics = (abc: string): NoteGroupInterface => {
|
|
164
185
|
const notes: string[] = [];
|
|
165
186
|
const lyrics: string[] = [];
|
|
166
187
|
abc.split("\n")
|
|
@@ -176,40 +197,13 @@ export const extractNotesAndLyrics = (abc: string): NoteGroupInterface => {
|
|
|
176
197
|
return {
|
|
177
198
|
notes: notes.join(" "),
|
|
178
199
|
lyrics: lyrics.join(" ")
|
|
179
|
-
}
|
|
180
|
-
};
|
|
181
|
-
|
|
182
|
-
export const addInfoFieldsToMelody = (song: AbcSong, abc: string): string => {
|
|
183
|
-
let result = "";
|
|
184
|
-
// See for following order of fields: https://abcnotation.com/wiki/abc:standard:v2.1#description_of_information_fields
|
|
185
|
-
result += song.referenceNumber === undefined ? "" : "X:" + song.referenceNumber + "\n";
|
|
186
|
-
result += song.title === undefined ? "" : "T:" + song.title + "\n";
|
|
187
|
-
result += song.area === undefined ? "" : "A:" + song.area + "\n";
|
|
188
|
-
result += song.book === undefined ? "" : "B:" + song.book + "\n";
|
|
189
|
-
result += song.composer === undefined ? "" : "C:" + song.composer + "\n";
|
|
190
|
-
result += song.discography === undefined ? "" : "D:" + song.discography + "\n";
|
|
191
|
-
result += song.fileUrl === undefined ? "" : "F:" + song.fileUrl + "\n";
|
|
192
|
-
result += song.group === undefined ? "" : "G:" + song.group + "\n";
|
|
193
|
-
result += song.history === undefined ? "" : "H:" + song.history + "\n";
|
|
194
|
-
result += song.instruction === undefined ? "" : "I:" + song.instruction + "\n";
|
|
195
|
-
result += song.key === undefined ? "" : "K:" + song.key + "\n";
|
|
196
|
-
result += song.unitNoteLength === undefined ? "" : "L:" + song.unitNoteLength + "\n";
|
|
197
|
-
result += song.meter === undefined ? "" : "M:" + song.meter + "\n";
|
|
198
|
-
result += song.macro === undefined ? "" : "m:" + song.macro + "\n";
|
|
199
|
-
result += song.notes === undefined ? "" : "N:" + song.notes + "\n";
|
|
200
|
-
result += song.origin === undefined ? "" : "O:" + song.origin + "\n";
|
|
201
|
-
result += song.parts === undefined ? "" : "P:" + song.parts + "\n";
|
|
202
|
-
result += song.tempo === undefined ? "" : "Q:" + song.tempo + "\n";
|
|
203
|
-
result += song.rhythm === undefined ? "" : "R:" + song.rhythm + "\n";
|
|
204
|
-
result += song.remark === undefined ? "" : "r:" + song.remark + "\n";
|
|
205
|
-
result += song.source === undefined ? "" : "S:" + song.source + "\n";
|
|
206
|
-
result += song.symbolLine === undefined ? "" : "s:" + song.symbolLine + "\n";
|
|
207
|
-
result += song.userDefined === undefined ? "" : "U:" + song.userDefined + "\n";
|
|
208
|
-
result += song.voice === undefined ? "" : "V:" + song.voice + "\n";
|
|
209
|
-
result += song.transcription === undefined ? "" : "Z:" + song.transcription + "\n";
|
|
210
|
-
return result + abc;
|
|
200
|
+
};
|
|
211
201
|
};
|
|
212
202
|
|
|
203
|
+
/**
|
|
204
|
+
* Converts and validates an ABC notation string into a TuneObject.
|
|
205
|
+
* @param abc
|
|
206
|
+
*/
|
|
213
207
|
export const convertStringToAbcTune = (abc: string): TuneObject => {
|
|
214
208
|
const objectArray: TuneObjectArray = ABCJS.parseOnly(abc);
|
|
215
209
|
// Convert types
|
|
@@ -218,6 +212,9 @@ export const convertStringToAbcTune = (abc: string): TuneObject => {
|
|
|
218
212
|
validate(object != null, "Tune object may not be null");
|
|
219
213
|
validate(object.length > 0, "Tune object may not be empty");
|
|
220
214
|
validate(object[0].lines != null, "Tune object lines may not be null");
|
|
215
|
+
|
|
216
|
+
object[0].lines = object[0].lines.filter(it => it.staff); // Remove empty lines without staff
|
|
217
|
+
|
|
221
218
|
validate(object[0].lines.length > 0, "Tune object lines are empty");
|
|
222
219
|
validate(object[0].lines[0].staff != null, "Staffs may not be null");
|
|
223
220
|
validate(object[0].lines[0].staff!!.length > 0, "Staffs are empty");
|
|
@@ -246,8 +243,17 @@ const processAbcLyrics = (object: Array<TuneObject>) => {
|
|
|
246
243
|
);
|
|
247
244
|
};
|
|
248
245
|
|
|
249
|
-
|
|
250
|
-
|
|
246
|
+
/**
|
|
247
|
+
* Combine multi line lyrics line with a multi line melody into a single ABC notation string.
|
|
248
|
+
* @param melody
|
|
249
|
+
* @param lyrics
|
|
250
|
+
* @param options
|
|
251
|
+
*/
|
|
252
|
+
export const combineMelodyAndLyrics = (
|
|
253
|
+
melody: string,
|
|
254
|
+
lyrics: string,
|
|
255
|
+
options: { trimLines?: boolean } = { trimLines: false },
|
|
256
|
+
): string => {
|
|
251
257
|
const song = new AbcSong();
|
|
252
258
|
const rawMelody = extractInfoFields(melody, song);
|
|
253
259
|
|
|
@@ -255,6 +261,13 @@ export const combineMelodyAndLyrics = (melody: string, lyrics: string): string =
|
|
|
255
261
|
.replaceAll(/\n+/g, "\n")
|
|
256
262
|
.trim()
|
|
257
263
|
.split("\n")
|
|
264
|
+
.map(it => it.trim())
|
|
265
|
+
.map(it => options.trimLines
|
|
266
|
+
? it
|
|
267
|
+
.replaceAll(/(^y+|y+$)*/gi, "")
|
|
268
|
+
.replaceAll(/ *y* *(\|+]*) *y* */gi, " $1 ")
|
|
269
|
+
.trim()
|
|
270
|
+
: it);
|
|
258
271
|
const lyricLines = lyrics
|
|
259
272
|
.replaceAll(/\n+/g, "\n")
|
|
260
273
|
.trim()
|
|
@@ -12,7 +12,7 @@ export type AbcType =
|
|
|
12
12
|
| "bar_thick_thin"
|
|
13
13
|
| "bar_right_repeat"
|
|
14
14
|
| "bar_left_repeat"
|
|
15
|
-
| "
|
|
15
|
+
| "bar_dbl_repeat";
|
|
16
16
|
export type AbcElementType = "note" | "bar";
|
|
17
17
|
export type Clef =
|
|
18
18
|
"treble"
|
|
@@ -99,6 +99,7 @@ export interface VoiceItemBar {
|
|
|
99
99
|
type: AbcType;
|
|
100
100
|
startChar: number;
|
|
101
101
|
endChar: number;
|
|
102
|
+
startEnding?: string; // Labels the repeat section
|
|
102
103
|
}
|
|
103
104
|
|
|
104
105
|
export interface NoteProperties {
|
|
@@ -107,6 +108,8 @@ export interface NoteProperties {
|
|
|
107
108
|
lyric?: AbcLyric[];
|
|
108
109
|
chord?: AbcChord[];
|
|
109
110
|
rest?: AbcRest;
|
|
111
|
+
startBeam?: boolean;
|
|
112
|
+
endBeam?: boolean;
|
|
110
113
|
}
|
|
111
114
|
|
|
112
115
|
export interface VoiceItemNote extends NoteProperties {
|
|
@@ -308,7 +311,7 @@ export class AbcSong {
|
|
|
308
311
|
};
|
|
309
312
|
}
|
|
310
313
|
|
|
311
|
-
export
|
|
312
|
-
notes: string
|
|
314
|
+
export type NoteGroupInterface = {
|
|
315
|
+
notes: string
|
|
313
316
|
lyrics: string
|
|
314
317
|
}
|