abcjs 6.4.1 → 6.4.3

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.
Files changed (48) hide show
  1. package/LICENSE.md +1 -1
  2. package/RELEASE.md +46 -0
  3. package/dist/abcjs-basic-min.js +2 -2
  4. package/dist/abcjs-basic-min.js.LICENSE +1 -1
  5. package/dist/abcjs-basic.js +1271 -1179
  6. package/dist/abcjs-basic.js.map +1 -1
  7. package/dist/abcjs-plugin-min.js +2 -2
  8. package/dist/abcjs-plugin-min.js.LICENSE +1 -1
  9. package/index.js +1 -1
  10. package/license.js +1 -1
  11. package/package.json +1 -1
  12. package/plugin.js +1 -1
  13. package/src/api/abc_tunebook.js +1 -2
  14. package/src/api/abc_tunebook_svg.js +0 -1
  15. package/src/data/abc_tune.js +2 -0
  16. package/src/midi/abc_midi_create.js +22 -7
  17. package/src/parse/abc_common.js +3 -11
  18. package/src/parse/abc_parse.js +1 -1
  19. package/src/parse/abc_parse_directive.js +44 -3
  20. package/src/parse/abc_parse_header.js +6 -4
  21. package/src/parse/abc_parse_key_voice.js +10 -6
  22. package/src/parse/abc_parse_music.js +54 -22
  23. package/src/parse/tune-builder.js +675 -643
  24. package/src/synth/abc_midi_flattener.js +3 -1
  25. package/src/synth/abc_midi_sequencer.js +18 -3
  26. package/src/synth/chord-track.js +90 -18
  27. package/src/synth/create-synth-control.js +1 -2
  28. package/src/tablatures/abc_tablatures.js +184 -0
  29. package/src/tablatures/instruments/string-patterns.js +266 -268
  30. package/src/tablatures/instruments/string-tablature.js +38 -35
  31. package/src/tablatures/instruments/tab-note.js +186 -181
  32. package/src/tablatures/instruments/tab-notes.js +30 -35
  33. package/src/tablatures/instruments/tab-string.js +43 -25
  34. package/src/tablatures/render/tab-absolute-elements.js +303 -0
  35. package/src/tablatures/render/tab-renderer.js +244 -0
  36. package/src/test/abc_parser_lint.js +2 -3
  37. package/src/write/creation/abstract-engraver.js +1 -1
  38. package/src/write/creation/elements/tie-element.js +26 -0
  39. package/src/write/engraver-controller.js +1 -1
  40. package/src/write/layout/set-upper-and-lower-elements.js +8 -0
  41. package/test.js +1 -1
  42. package/types/index.d.ts +2 -2
  43. package/version.js +1 -1
  44. package/src/api/abc_tablatures.js +0 -184
  45. package/src/tablatures/instruments/tab-string-patterns.js +0 -23
  46. package/src/tablatures/tab-absolute-elements.js +0 -301
  47. package/src/tablatures/tab-common.js +0 -29
  48. package/src/tablatures/tab-renderer.js +0 -259
@@ -1,278 +1,275 @@
1
- const {noteToMidi} = require('../../synth/note-to-midi');
1
+ const { noteToMidi } = require('../../synth/note-to-midi');
2
2
  var TabNote = require('./tab-note');
3
- var TabNotes = require('./tab-notes');
3
+ var tabNotes = require('./tab-notes');
4
4
 
5
5
 
6
6
  function buildCapo(self) {
7
- var capoTuning = null;
8
- var tuning = self.tuning;
9
- if (self.capo > 0) {
10
- capoTuning = [];
11
- for (var iii = 0; iii < tuning.length; iii++) {
12
- var curNote = new TabNote.TabNote(tuning[iii]);
13
- for (var jjj = 0; jjj < self.capo; jjj++) {
14
- curNote = curNote.nextNote();
15
- }
16
- capoTuning[iii] = curNote.emit();
17
- }
18
- }
19
- return capoTuning;
7
+ var capoTuning = null;
8
+ var tuning = self.tuning;
9
+ if (self.capo > 0) {
10
+ capoTuning = [];
11
+ for (var iii = 0; iii < tuning.length; iii++) {
12
+ var curNote = new TabNote(tuning[iii]);
13
+ for (var jjj = 0; jjj < self.capo; jjj++) {
14
+ curNote = curNote.nextNote();
15
+ }
16
+ capoTuning[iii] = curNote.emit();
17
+ }
18
+ }
19
+ return capoTuning;
20
20
  }
21
21
 
22
22
  function buildPatterns(self) {
23
- var strings = [];
24
- var tuning = self.tuning;
25
- if (self.capo > 0) {
26
- tuning = self.capoTuning;
27
- }
28
- var pos = tuning.length - 1;
29
- for (var iii = 0; iii < tuning.length; iii++) {
30
- var nextNote = self.highestNote; // highest handled note
31
- if (iii != tuning.length - 1) {
32
- nextNote = tuning[iii + 1];
33
- }
34
- var tabNotes = new TabNotes(tuning[iii],nextNote);
35
- var stringNotes = tabNotes.build();
36
- if (stringNotes.error) {
37
- return stringNotes;
38
- }
39
- strings[pos--] = stringNotes;
40
- }
41
- return strings;
23
+ var strings = [];
24
+ var tuning = self.tuning;
25
+ if (self.capo > 0) {
26
+ tuning = self.capoTuning;
27
+ }
28
+ var pos = tuning.length - 1;
29
+ for (var iii = 0; iii < tuning.length; iii++) {
30
+ var nextNote = self.highestNote; // highest handled note
31
+ if (iii != tuning.length - 1) {
32
+ nextNote = tuning[iii + 1];
33
+ }
34
+ var stringNotes = tabNotes(tuning[iii], nextNote);
35
+ if (stringNotes.error) {
36
+ return stringNotes;
37
+ }
38
+ strings[pos--] = stringNotes;
39
+ }
40
+ return strings;
42
41
  }
43
42
 
44
43
 
45
44
  function buildSecond(first) {
46
- var seconds = [];
47
- seconds[0] = [];
48
- var strings = first.strings;
49
- for (var iii = 1; iii < strings.length; iii++) {
50
- seconds[iii] = strings[iii - 1];
51
- }
52
- return seconds;
45
+ var seconds = [];
46
+ seconds[0] = [];
47
+ var strings = first.strings;
48
+ for (var iii = 1; iii < strings.length; iii++) {
49
+ seconds[iii] = strings[iii - 1];
50
+ }
51
+ return seconds;
53
52
  }
54
53
 
55
54
  function sameString(self, chord) {
56
- for (var jjjj = 0; jjjj < chord.length - 1; jjjj++) {
57
- var curPos = chord[jjjj];
58
- var nextPos = chord[jjjj + 1];
59
- if (curPos.str == nextPos.str) {
60
- // same String
61
- // => change lower pos
62
- if (curPos.str == self.strings.length - 1) {
63
- // Invalid tab Chord position for instrument
64
- curPos.num = "?";
65
- nextPos.num = "?";
66
- return;
67
- }
68
- // change lower pitch on lowest string
69
- if (nextPos.num < curPos.num) {
70
- nextPos.str++;
71
- nextPos = noteToNumber(self,
72
- nextPos.note,
73
- nextPos.str,
74
- self.secondPos,
75
- self.strings[nextPos.str].length
76
- );
77
- } else {
78
- curPos.str++;
79
- curPos = noteToNumber(self,
80
- curPos.note,
81
- curPos.str,
82
- self.secondPos,
83
- self.strings[curPos.str].length
84
- );
85
- }
86
- // update table
87
- chord[jjjj] = curPos;
88
- chord[jjjj + 1] = nextPos;
89
- }
90
- }
91
- return null;
55
+ for (var jjjj = 0; jjjj < chord.length - 1; jjjj++) {
56
+ var curPos = chord[jjjj];
57
+ var nextPos = chord[jjjj + 1];
58
+ if (curPos.str == nextPos.str) {
59
+ // same String
60
+ // => change lower pos
61
+ if (curPos.str == self.strings.length - 1) {
62
+ // Invalid tab Chord position for instrument
63
+ curPos.num = "?";
64
+ nextPos.num = "?";
65
+ return;
66
+ }
67
+ // change lower pitch on lowest string
68
+ if (nextPos.num < curPos.num) {
69
+ nextPos.str++;
70
+ nextPos = noteToNumber(self,
71
+ nextPos.note,
72
+ nextPos.str,
73
+ self.secondPos,
74
+ self.strings[nextPos.str].length
75
+ );
76
+ } else {
77
+ curPos.str++;
78
+ curPos = noteToNumber(self,
79
+ curPos.note,
80
+ curPos.str,
81
+ self.secondPos,
82
+ self.strings[curPos.str].length
83
+ );
84
+ }
85
+ // update table
86
+ chord[jjjj] = curPos;
87
+ chord[jjjj + 1] = nextPos;
88
+ }
89
+ }
90
+ return null;
92
91
  }
93
92
 
94
93
  function handleChordNotes(self, notes) {
95
- var retNotes = [];
96
- for (var iiii = 0; iiii < notes.length; iiii++) {
97
- if (notes[iiii].endTie)
98
- continue;
99
- var note = new TabNote.TabNote(notes[iiii].name, self.clefTranspose);
100
- note.checkKeyAccidentals(self.accidentals, self.measureAccidentals)
101
- var curPos = toNumber(self, note);
102
- retNotes.push(curPos);
103
- }
104
- sameString(self, retNotes);
105
- return retNotes;
94
+ var retNotes = [];
95
+ for (var iiii = 0; iiii < notes.length; iiii++) {
96
+ if (notes[iiii].endTie)
97
+ continue;
98
+ var note = new TabNote(notes[iiii].name, self.clefTranspose);
99
+ note.checkKeyAccidentals(self.accidentals, self.measureAccidentals)
100
+ var curPos = toNumber(self, note);
101
+ retNotes.push(curPos);
102
+ }
103
+ sameString(self, retNotes);
104
+ return retNotes;
106
105
  }
107
106
 
108
- function noteToNumber(self, note, stringNumber, secondPosition , firstSize) {
109
- var strings = self.strings;
110
- note.checkKeyAccidentals(self.accidentals, self.measureAccidentals) ;
111
- if (secondPosition) {
112
- strings = secondPosition;
113
- }
114
- var noteName = note.emitNoAccidentals();
115
- var num = strings[stringNumber].indexOf(noteName);
116
- var acc = note.acc;
117
- if (num != -1) {
118
- if (secondPosition) {
119
- num += firstSize;
120
- }
121
- if ( (note.isFlat || note.acc == -1) && (num == 0)) {
122
- // flat on 0 pos => previous string 7th position
123
- var noteEquiv = note.getAccidentalEquiv();
124
- stringNumber++;
125
- num = strings[stringNumber].indexOf(noteEquiv.emit());
126
- acc = 0;
127
- }
128
- return {
129
- num: (num + acc),
130
- str: stringNumber,
131
- note: note
132
- };
133
- }
134
- return null;
107
+ function noteToNumber(self, note, stringNumber, secondPosition, firstSize) {
108
+ var strings = self.strings;
109
+ note.checkKeyAccidentals(self.accidentals, self.measureAccidentals);
110
+ if (secondPosition) {
111
+ strings = secondPosition;
112
+ }
113
+ var noteName = note.emitNoAccidentals();
114
+ var num = strings[stringNumber].indexOf(noteName);
115
+ var acc = note.acc;
116
+ if (num != -1) {
117
+ if (secondPosition) {
118
+ num += firstSize;
119
+ }
120
+ if ((note.isFlat || note.acc == -1) && (num == 0)) {
121
+ // flat on 0 pos => previous string 7th position
122
+ var noteEquiv = note.getAccidentalEquiv();
123
+ stringNumber++;
124
+ num = strings[stringNumber].indexOf(noteEquiv.emit());
125
+ acc = 0;
126
+ }
127
+ return {
128
+ num: (num + acc),
129
+ str: stringNumber,
130
+ note: note
131
+ };
132
+ }
133
+ return null;
135
134
  }
136
135
 
137
136
  function toNumber(self, note) {
138
- if (note.isAltered || note.natural) {
139
- var acc;
140
- if (note.isFlat) {
141
- if (note.isDouble)
142
- acc = "__"
143
- else
144
- acc = "_"
145
- } else if (note.isSharp) {
146
- if (note.isDouble)
147
- acc = "^^"
148
- else
149
- acc = "^"
150
- } else if (note.natural)
151
- acc = "="
152
- self.measureAccidentals[note.name.toUpperCase()] = acc
153
- }
154
- for (var i = self.stringPitches.length-1; i >= 0; i--) {
155
- if (note.pitch + note.pitchAltered >= self.stringPitches[i]) {
156
- var num = note.pitch + note.pitchAltered - self.stringPitches[i]
157
- if (note.quarter === '^') num -= 0.5
158
- else if (note.quarter === "v") num += 0.5
159
- return {
160
- num: Math.round(num),
161
- str: self.stringPitches.length-1-i, // reverse the strings because string 0 is on the bottom
162
- note: note
163
- }
164
- }
165
- }
166
- return {
167
- num: "?",
168
- str: self.stringPitches.length-1,
169
- note: note,
170
- };
137
+ if (note.isAltered || note.natural) {
138
+ var acc;
139
+ if (note.isFlat) {
140
+ if (note.isDouble)
141
+ acc = "__"
142
+ else
143
+ acc = "_"
144
+ } else if (note.isSharp) {
145
+ if (note.isDouble)
146
+ acc = "^^"
147
+ else
148
+ acc = "^"
149
+ } else if (note.natural)
150
+ acc = "="
151
+ self.measureAccidentals[note.name.toUpperCase()] = acc
152
+ }
153
+ for (var i = self.stringPitches.length - 1; i >= 0; i--) {
154
+ if (note.pitch + note.pitchAltered >= self.stringPitches[i]) {
155
+ var num = note.pitch + note.pitchAltered - self.stringPitches[i]
156
+ if (note.quarter === '^') num -= 0.5
157
+ else if (note.quarter === "v") num += 0.5
158
+ return {
159
+ num: Math.round(num),
160
+ str: self.stringPitches.length - 1 - i, // reverse the strings because string 0 is on the bottom
161
+ note: note
162
+ }
163
+ }
164
+ }
165
+ return {
166
+ num: "?",
167
+ str: self.stringPitches.length - 1,
168
+ note: note,
169
+ };
171
170
  }
172
171
 
173
172
  StringPatterns.prototype.stringToPitch = function (stringNumber) {
174
- var startingPitch = 5.3;
175
- var bottom = this.strings.length - 1;
176
- return startingPitch + ((bottom - stringNumber) * this.linePitch);
173
+ var startingPitch = 5.3;
174
+ var bottom = this.strings.length - 1;
175
+ return startingPitch + ((bottom - stringNumber) * this.linePitch);
177
176
  };
178
177
 
179
- function invalidNumber( retNotes , note ) {
180
- var number = {
181
- num: "?",
182
- str: 0,
183
- note: note
184
- };
185
- retNotes.push(number);
186
- retNotes.error = note.emit() + ': unexpected note for instrument' ;
187
- }
178
+ function invalidNumber(retNotes, note) {
179
+ var number = {
180
+ num: "?",
181
+ str: 0,
182
+ note: note
183
+ };
184
+ retNotes.push(number);
185
+ retNotes.error = note.emit() + ': unexpected note for instrument';
186
+ }
188
187
 
189
188
  StringPatterns.prototype.notesToNumber = function (notes, graces) {
190
- var note;
191
- var number;
192
- var error = null;
193
- var retNotes = null;
194
- if (notes) {
195
- retNotes = [];
196
- if (notes.length > 1) {
197
- retNotes = handleChordNotes(this, notes);
198
- if (retNotes.error) {
199
- error = retNotes.error;
200
- }
201
- } else {
202
- if (!notes[0].endTie) {
203
- note = new TabNote.TabNote(notes[0].name, this.clefTranspose);
204
- note.checkKeyAccidentals(this.accidentals, this.measureAccidentals)
205
- number = toNumber(this, note);
206
- if (number) {
207
- retNotes.push(number);
208
- } else {
209
- invalidNumber(retNotes, note);
210
- error = retNotes.error;
211
- }
212
- }
213
- }
214
- }
215
- if (error) return retNotes;
216
- var retGraces = null;
217
- if (graces) {
218
- retGraces = [];
219
- for (var iiii = 0; iiii < graces.length; iiii++) {
220
- note = new TabNote.TabNote(graces[iiii].name, this.clefTranspose);
221
- note.checkKeyAccidentals(this.accidentals, this.measureAccidentals)
222
- number = toNumber(this, note);
223
- if (number) {
224
- retGraces.push(number);
225
- } else {
226
- invalidNumber(retGraces, note);
227
- error = retNotes.error;
228
- }
229
- }
230
- }
231
-
232
- return {
233
- notes: retNotes,
234
- graces: retGraces,
235
- error: error
236
- };
189
+ var note;
190
+ var number;
191
+ var error = null;
192
+ var retNotes = null;
193
+ if (notes) {
194
+ retNotes = [];
195
+ if (notes.length > 1) {
196
+ retNotes = handleChordNotes(this, notes);
197
+ if (retNotes.error) {
198
+ error = retNotes.error;
199
+ }
200
+ } else {
201
+ if (!notes[0].endTie) {
202
+ note = new TabNote(notes[0].name, this.clefTranspose);
203
+ note.checkKeyAccidentals(this.accidentals, this.measureAccidentals)
204
+ number = toNumber(this, note);
205
+ if (number) {
206
+ retNotes.push(number);
207
+ } else {
208
+ invalidNumber(retNotes, note);
209
+ error = retNotes.error;
210
+ }
211
+ }
212
+ }
213
+ }
214
+ if (error) return retNotes;
215
+ var retGraces = null;
216
+ if (graces) {
217
+ retGraces = [];
218
+ for (var iiii = 0; iiii < graces.length; iiii++) {
219
+ note = new TabNote(graces[iiii].name, this.clefTranspose);
220
+ note.checkKeyAccidentals(this.accidentals, this.measureAccidentals)
221
+ number = toNumber(this, note);
222
+ if (number) {
223
+ retGraces.push(number);
224
+ } else {
225
+ invalidNumber(retGraces, note);
226
+ error = retNotes.error;
227
+ }
228
+ }
229
+ }
230
+
231
+ return {
232
+ notes: retNotes,
233
+ graces: retGraces,
234
+ error: error
235
+ };
237
236
  };
238
237
 
239
238
  StringPatterns.prototype.toString = function () {
240
- var arr = []
241
- for (var i = 0; i < this.tuning.length; i++) {
242
- var str = this.tuning[i].replaceAll(',', '').replaceAll("'", '').toUpperCase();
243
- if (str[0] === '_') str = str[1] + 'b '
244
- else if (str[0] === '^') str = str[1] + "# "
245
- arr.push(str)
246
- }
247
- return arr.join('');
239
+ var arr = []
240
+ for (var i = 0; i < this.tuning.length; i++) {
241
+ var str = this.tuning[i].replaceAll(',', '').replaceAll("'", '').toUpperCase();
242
+ if (str[0] === '_') str = str[1] + 'b '
243
+ else if (str[0] === '^') str = str[1] + "# "
244
+ arr.push(str)
245
+ }
246
+ return arr.join('');
248
247
  };
249
248
 
250
249
  StringPatterns.prototype.tabInfos = function (plugin) {
251
- var _super = plugin._super;
252
- var name = _super.params.label;
253
- if (name) {
254
- var tunePos = name.indexOf('%T');
255
- var tuning = "";
256
- if (tunePos != -1) {
257
- tuning = this.toString();
258
- if (plugin.capo > 0) {
259
- tuning += ' capo:' + plugin.capo;
260
- }
261
- name = name.replace('%T', tuning);
262
- }
263
- return name;
264
- }
265
- return '';
250
+ var name = plugin.params.label;
251
+ if (name) {
252
+ var tunePos = name.indexOf('%T');
253
+ var tuning = "";
254
+ if (tunePos != -1) {
255
+ tuning = this.toString();
256
+ if (plugin.capo > 0) {
257
+ tuning += ' capo:' + plugin.capo;
258
+ }
259
+ name = name.replace('%T', tuning);
260
+ }
261
+ return name;
262
+ }
263
+ return '';
266
264
  };
267
265
 
268
266
  // MAE 27 Nov 2023
269
267
  StringPatterns.prototype.suppress = function (plugin) {
270
- var _super = plugin._super;
271
- var suppress = _super.params.suppress;
272
- if (suppress){
273
- return true;
274
- }
275
- return false;
268
+ var suppress = plugin.params.suppress;
269
+ if (suppress) {
270
+ return true;
271
+ }
272
+ return false;
276
273
  };
277
274
  // MAE 27 Nov 2023 End
278
275
 
@@ -284,38 +281,39 @@ StringPatterns.prototype.suppress = function (plugin) {
284
281
  * @param {*} highestNote
285
282
  */
286
283
  function StringPatterns(plugin) {
287
- var tuning = plugin.tuning;
288
- var capo = plugin.capo;
289
- var highestNote = plugin._super.params.highestNote;
290
- this.linePitch = plugin.linePitch;
291
- this.highestNote = "a'";
292
- if (highestNote) {
293
- // override default
294
- this.highestNote = highestNote;
295
- }
296
- this.measureAccidentals = {}
297
- this.capo = 0;
298
- if (capo) {
299
- this.capo = parseInt(capo,10);
300
- }
301
- this.transpose = plugin.transpose ? plugin.transpose : 0
302
- this.tuning = tuning;
303
- this.stringPitches = []
304
- for (var i = 0; i < this.tuning.length; i++) {
305
- var pitch = noteToMidi(this.tuning[i]) + this.capo
306
- this.stringPitches.push(pitch)
307
- }
308
- if (this.capo > 0) {
309
- this.capoTuning = buildCapo(this);
310
- }
311
- this.strings = buildPatterns(this);
312
- if (this.strings.error) {
313
- plugin._super.setError(this.strings.error);
314
- plugin.inError = true;
315
- return;
316
- }
317
- // second position pattern per string
318
- this.secondPos = buildSecond(this);
284
+ //console.log("INIT StringPatterns constructor")
285
+ var tuning = plugin.tuning;
286
+ var capo = plugin.capo;
287
+ var highestNote = plugin.params.highestNote;
288
+ this.linePitch = plugin.linePitch;
289
+ this.highestNote = "a'";
290
+ if (highestNote) {
291
+ // override default
292
+ this.highestNote = highestNote;
293
+ }
294
+ this.measureAccidentals = {}
295
+ this.capo = 0;
296
+ if (capo) {
297
+ this.capo = parseInt(capo, 10);
298
+ }
299
+ this.transpose = plugin.transpose ? plugin.transpose : 0
300
+ this.tuning = tuning;
301
+ this.stringPitches = []
302
+ for (var i = 0; i < this.tuning.length; i++) {
303
+ var pitch = noteToMidi(this.tuning[i]) + this.capo
304
+ this.stringPitches.push(pitch)
305
+ }
306
+ if (this.capo > 0) {
307
+ this.capoTuning = buildCapo(this);
308
+ }
309
+ this.strings = buildPatterns(this);
310
+ if (this.strings.error) {
311
+ plugin.setError(this.strings.error);
312
+ plugin.inError = true;
313
+ return;
314
+ }
315
+ // second position pattern per string
316
+ this.secondPos = buildSecond(this);
319
317
  }
320
318
 
321
319