abcjs 6.1.9 → 6.2.1
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/LICENSE.md +1 -1
- package/RELEASE.md +58 -0
- package/dist/abcjs-basic-min.js +2 -2
- package/dist/abcjs-basic-min.js.LICENSE +1 -1
- package/dist/abcjs-basic.js +4505 -4556
- package/dist/abcjs-basic.js.map +1 -1
- package/dist/abcjs-plugin-min.js +2 -2
- package/dist/abcjs-plugin-min.js.LICENSE +1 -1
- package/index.js +2 -2
- package/license.js +1 -1
- package/package.json +1 -1
- package/plugin.js +2 -2
- package/src/api/abc_timing_callbacks.js +8 -4
- package/src/api/abc_tunebook_svg.js +1 -2
- package/src/data/abc_tune.js +3 -3
- package/src/parse/abc_common.js +0 -47
- package/src/parse/abc_parse.js +16 -16
- package/src/parse/abc_parse_book.js +3 -3
- package/src/parse/abc_parse_directive.js +26 -7
- package/src/parse/abc_parse_header.js +11 -9
- package/src/parse/abc_parse_key_voice.js +17 -17
- package/src/parse/abc_parse_music.js +88 -105
- package/src/parse/abc_tokenizer.js +60 -60
- package/src/parse/tune-builder.js +19 -14
- package/src/synth/abc_midi_flattener.js +25 -9
- package/src/synth/create-synth.js +71 -4
- package/src/synth/load-note.js +1 -1
- package/src/synth/note-to-midi.js +50 -0
- package/src/synth/place-note.js +10 -2
- package/src/tablatures/instruments/guitar/tab-guitar.js +0 -2
- package/src/tablatures/instruments/string-patterns.js +47 -29
- package/src/tablatures/instruments/tab-note.js +26 -103
- package/src/tablatures/instruments/violin/tab-violin.js +0 -2
- package/src/tablatures/tab-absolute-elements.js +9 -31
- package/src/tablatures/tab-renderer.js +2 -2
- package/src/test/abc_parser_lint.js +7 -4
- package/src/write/README.md +31 -0
- package/src/write/creation/abstract-engraver.js +1036 -0
- package/src/write/creation/add-chord.js +102 -0
- package/src/write/{add-text-if.js → creation/add-text-if.js} +6 -6
- package/src/write/{calcHeight.js → creation/calc-height.js} +2 -2
- package/src/write/creation/create-clef.js +72 -0
- package/src/write/creation/create-key-signature.js +31 -0
- package/src/write/creation/create-note-head.js +107 -0
- package/src/write/creation/create-time-signature.js +55 -0
- package/src/write/creation/decoration.js +357 -0
- package/src/write/{abc_absolute_element.js → creation/elements/absolute-element.js} +14 -15
- package/src/write/creation/elements/beam-element.js +113 -0
- package/src/write/{bottom-text.js → creation/elements/bottom-text.js} +14 -15
- package/src/write/{abc_brace_element.js → creation/elements/brace-element.js} +5 -5
- package/src/write/creation/elements/free-text.js +41 -0
- package/src/write/{abc_relative_element.js → creation/elements/relative-element.js} +7 -7
- package/src/write/{separator.js → creation/elements/separator.js} +2 -2
- package/src/write/{abc_staff_group_element.js → creation/elements/staff-group-element.js} +4 -4
- package/src/write/{subtitle.js → creation/elements/subtitle.js} +3 -3
- package/src/write/creation/elements/tempo-element.js +63 -0
- package/src/write/{abc_tie_element.js → creation/elements/tie-element.js} +15 -11
- package/src/write/{top-text.js → creation/elements/top-text.js} +12 -12
- package/src/write/creation/elements/triplet-element.js +28 -0
- package/src/write/{abc_voice_element.js → creation/elements/voice-element.js} +3 -3
- package/src/write/creation/glyphs.js +226 -0
- package/src/write/creation/translate-chord.js +37 -0
- package/src/write/draw/absolute.js +5 -5
- package/src/write/draw/beam.js +8 -8
- package/src/write/draw/brace.js +33 -33
- package/src/write/draw/crescendo.js +4 -4
- package/src/write/draw/debug-box.js +1 -1
- package/src/write/draw/draw.js +7 -7
- package/src/write/draw/dynamics.js +2 -2
- package/src/write/draw/ending.js +6 -6
- package/src/write/draw/glissando.js +17 -17
- package/src/write/draw/group-elements.js +51 -51
- package/src/write/draw/horizontal-line.js +9 -9
- package/src/write/draw/non-music.js +1 -1
- package/src/write/draw/print-line.js +25 -16
- package/src/write/draw/print-stem.js +15 -5
- package/src/write/draw/print-symbol.js +12 -12
- package/src/write/draw/print-vertical-line.js +8 -8
- package/src/write/draw/relative.js +17 -16
- package/src/write/draw/selectables.js +5 -5
- package/src/write/draw/separator.js +4 -4
- package/src/write/draw/set-paper-size.js +2 -2
- package/src/write/draw/sprintf.js +31 -31
- package/src/write/draw/staff-group.js +36 -30
- package/src/write/draw/staff-line.js +2 -2
- package/src/write/draw/staff.js +4 -4
- package/src/write/draw/tab-line.js +26 -26
- package/src/write/draw/tempo.js +30 -30
- package/src/write/draw/text.js +5 -5
- package/src/write/draw/tie.js +18 -18
- package/src/write/draw/triplet.js +6 -6
- package/src/write/draw/voice.js +16 -17
- package/src/write/{abc_engraver_controller.js → engraver-controller.js} +58 -51
- package/src/write/{classes.js → helpers/classes.js} +6 -6
- package/src/write/{get-font-and-attr.js → helpers/get-font-and-attr.js} +9 -7
- package/src/write/{get-text-size.js → helpers/get-text-size.js} +5 -5
- package/src/write/{set-class.js → helpers/set-class.js} +1 -1
- package/src/write/{abc_spacing.js → helpers/spacing.js} +1 -1
- package/src/write/{highlight.js → interactive/highlight.js} +1 -1
- package/src/write/{selection.js → interactive/selection.js} +34 -31
- package/src/write/{unhighlight.js → interactive/unhighlight.js} +1 -1
- package/src/write/layout/beam.js +13 -13
- package/src/write/layout/get-left-edge-of-staff.js +4 -4
- package/src/write/layout/layout.js +74 -74
- package/src/write/layout/{setUpperAndLowerElements.js → set-upper-and-lower-elements.js} +8 -8
- package/src/write/layout/{staffGroup.js → staff-group.js} +32 -32
- package/src/write/layout/triplet.js +4 -4
- package/src/write/layout/{VoiceElements.js → voice-elements.js} +23 -23
- package/src/write/layout/voice.js +6 -6
- package/src/write/{abc_renderer.js → renderer.js} +36 -32
- package/src/write/svg.js +35 -35
- package/test.js +2 -2
- package/types/index.d.ts +37 -8
- package/version.js +1 -1
- package/src/tablatures/instruments/guitar/guitar-fonts.js +0 -19
- package/src/tablatures/instruments/violin/violin-fonts.js +0 -19
- package/src/tablatures/transposer.js +0 -110
- package/src/write/abc_abstract_engraver.js +0 -1026
- package/src/write/abc_beam_element.js +0 -113
- package/src/write/abc_create_clef.js +0 -72
- package/src/write/abc_create_key_signature.js +0 -33
- package/src/write/abc_create_note_head.js +0 -107
- package/src/write/abc_create_time_signature.js +0 -55
- package/src/write/abc_decoration.js +0 -357
- package/src/write/abc_glyphs.js +0 -224
- package/src/write/abc_tempo_element.js +0 -63
- package/src/write/abc_triplet_element.js +0 -28
- package/src/write/add-chord.js +0 -103
- package/src/write/format-jazz-chord.js +0 -15
- package/src/write/free-text.js +0 -41
- /package/src/write/{abc_crescendo_element.js → creation/elements/crescendo-element.js} +0 -0
- /package/src/write/{abc_dynamic_decoration.js → creation/elements/dynamic-decoration.js} +0 -0
- /package/src/write/{abc_ending_element.js → creation/elements/ending-element.js} +0 -0
- /package/src/write/{abc_glissando_element.js → creation/elements/glissando-element.js} +0 -0
- /package/src/write/layout/{getBarYAt.js → get-bar-y-at.js} +0 -0
|
@@ -26,11 +26,13 @@ function CreateSynth() {
|
|
|
26
26
|
self.audioBuffers = []; // cache of the buffers so starting play can be fast.
|
|
27
27
|
self.duration = undefined; // the duration of the tune in seconds.
|
|
28
28
|
self.isRunning = false; // whether there is currently a sound buffer running.
|
|
29
|
+
// self.options = undefined
|
|
29
30
|
|
|
30
31
|
// Load and cache all needed sounds
|
|
31
32
|
self.init = function(options) {
|
|
32
33
|
if (!options)
|
|
33
34
|
options = {};
|
|
35
|
+
// self.options = options
|
|
34
36
|
registerAudioContext(options.audioContext); // This works no matter what - if there is already an ac it is a nop; if the context is not passed in, then it creates one.
|
|
35
37
|
var startTime = activeAudioContext().currentTime;
|
|
36
38
|
self.debugCallback = options.debugCallback;
|
|
@@ -163,6 +165,9 @@ function CreateSynth() {
|
|
|
163
165
|
notes.push({ instrument: instrument, note: note });
|
|
164
166
|
});
|
|
165
167
|
});
|
|
168
|
+
if (self.debugCallback)
|
|
169
|
+
self.debugCallback("notes "+JSON.stringify(notes));
|
|
170
|
+
|
|
166
171
|
// If there are lots of notes, load them in batches
|
|
167
172
|
var batches = [];
|
|
168
173
|
var CHUNK = 256;
|
|
@@ -179,8 +184,13 @@ function CreateSynth() {
|
|
|
179
184
|
|
|
180
185
|
var index = 0;
|
|
181
186
|
var next = function() {
|
|
187
|
+
if (self.debugCallback)
|
|
188
|
+
self.debugCallback("loadBatch idx="+index+ " len="+batches.length);
|
|
189
|
+
|
|
182
190
|
if (index < batches.length) {
|
|
183
191
|
self._loadBatch(batches[index], self.soundFontUrl, startTime).then(function(data) {
|
|
192
|
+
if (self.debugCallback)
|
|
193
|
+
self.debugCallback("loadBatch then");
|
|
184
194
|
startTime = activeAudioContext().currentTime;
|
|
185
195
|
if (data) {
|
|
186
196
|
if (data.error)
|
|
@@ -192,6 +202,9 @@ function CreateSynth() {
|
|
|
192
202
|
next();
|
|
193
203
|
}, reject);
|
|
194
204
|
} else {
|
|
205
|
+
if (self.debugCallback)
|
|
206
|
+
self.debugCallback("resolve init");
|
|
207
|
+
|
|
195
208
|
resolve(results);
|
|
196
209
|
}
|
|
197
210
|
};
|
|
@@ -203,6 +216,8 @@ function CreateSynth() {
|
|
|
203
216
|
// This is called recursively to see if the sounds have loaded. The "delay" parameter is how long it has been since the original call.
|
|
204
217
|
var promises = [];
|
|
205
218
|
batch.forEach(function(item) {
|
|
219
|
+
if (self.debugCallback)
|
|
220
|
+
self.debugCallback("getNote " + item.instrument+':'+item.note);
|
|
206
221
|
promises.push(getNote(soundFontUrl, item.instrument, item.note, activeAudioContext()));
|
|
207
222
|
});
|
|
208
223
|
return Promise.all(promises).then(function(response) {
|
|
@@ -225,6 +240,8 @@ function CreateSynth() {
|
|
|
225
240
|
error.push(which + ' ' + oneResponse.message);
|
|
226
241
|
}
|
|
227
242
|
if (pending.length > 0) {
|
|
243
|
+
if (self.debugCallback)
|
|
244
|
+
self.debugCallback("pending " + JSON.stringify(pending));
|
|
228
245
|
// There was probably a second call for notes before the first one finished, so just retry a few times to see if they stop being pending.
|
|
229
246
|
// Retry quickly at first so that there isn't an unnecessary delay, but increase the delay each time.
|
|
230
247
|
if (!delay)
|
|
@@ -239,7 +256,9 @@ function CreateSynth() {
|
|
|
239
256
|
which = pending[i].split(":");
|
|
240
257
|
newBatch.push({instrument: which[0], note: which[1]});
|
|
241
258
|
}
|
|
242
|
-
self.
|
|
259
|
+
if (self.debugCallback)
|
|
260
|
+
self.debugCallback("retry " + JSON.stringify(newBatch));
|
|
261
|
+
self._loadBatch(newBatch, soundFontUrl, startTime, delay).then(function (response) {
|
|
243
262
|
resolve(response);
|
|
244
263
|
}).catch(function (error) {
|
|
245
264
|
reject(error);
|
|
@@ -250,11 +269,18 @@ function CreateSynth() {
|
|
|
250
269
|
var list = [];
|
|
251
270
|
for (var j = 0; j < batch.length; j++)
|
|
252
271
|
list.push(batch[j].instrument+'/'+batch[j].note)
|
|
253
|
-
|
|
272
|
+
if (self.debugCallback)
|
|
273
|
+
self.debugCallback("loadBatch timeout")
|
|
274
|
+
return Promise.reject(new Error("timeout attempting to load: " + list.join(", ")));
|
|
254
275
|
}
|
|
255
|
-
} else
|
|
276
|
+
} else {
|
|
277
|
+
if (self.debugCallback)
|
|
278
|
+
self.debugCallback("loadBatch resolve")
|
|
256
279
|
return Promise.resolve({loaded: loaded, cached: cached, error: error});
|
|
280
|
+
}
|
|
257
281
|
}).catch(function (error) {
|
|
282
|
+
if (self.debugCallback)
|
|
283
|
+
self.debugCallback("loadBatch catch "+error.message)
|
|
258
284
|
});
|
|
259
285
|
});
|
|
260
286
|
|
|
@@ -283,6 +309,8 @@ function CreateSynth() {
|
|
|
283
309
|
self.stop();
|
|
284
310
|
|
|
285
311
|
var noteMapTracks = createNoteMap(self.flattened);
|
|
312
|
+
// if (self.options.swing)
|
|
313
|
+
// addSwing(noteMapTracks, self.options.swing, self.beatsPerMeasure)
|
|
286
314
|
if (self.sequenceCallback)
|
|
287
315
|
self.sequenceCallback(noteMapTracks, self.callbackContext);
|
|
288
316
|
|
|
@@ -295,6 +323,8 @@ function CreateSynth() {
|
|
|
295
323
|
var panDistance = panDistances && panDistances.length > trackNumber ? panDistances[trackNumber] : 0;
|
|
296
324
|
noteMap.forEach(function(note) {
|
|
297
325
|
var key = note.instrument + ':' + note.pitch + ':' +note.volume + ':' + Math.round((note.end-note.start)*1000)/1000 + ':' + panDistance + ':' + tempoMultiplier + ':' + (note.cents ? note.cents : 0);
|
|
326
|
+
if (self.debugCallback)
|
|
327
|
+
self.debugCallback("noteMapTrack "+key)
|
|
298
328
|
if (!uniqueSounds[key])
|
|
299
329
|
uniqueSounds[key] = [];
|
|
300
330
|
uniqueSounds[key].push(note.start);
|
|
@@ -309,7 +339,7 @@ function CreateSynth() {
|
|
|
309
339
|
var parts = k.split(":");
|
|
310
340
|
var cents = parts[6] !== undefined ? parseFloat(parts[6]) : 0;
|
|
311
341
|
parts = {instrument: parts[0], pitch: parseInt(parts[1], 10), volume: parseInt(parts[2], 10), len: parseFloat(parts[3]), pan: parseFloat(parts[4]), tempoMultiplier: parseFloat(parts[5]), cents: cents};
|
|
312
|
-
allPromises.push(placeNote(audioBuffer, activeAudioContext().sampleRate, parts, uniqueSounds[k], self.soundFontVolumeMultiplier, self.programOffsets[parts.instrument], fadeTimeSec, self.noteEnd/1000));
|
|
342
|
+
allPromises.push(placeNote(audioBuffer, activeAudioContext().sampleRate, parts, uniqueSounds[k], self.soundFontVolumeMultiplier, self.programOffsets[parts.instrument], fadeTimeSec, self.noteEnd/1000, self.debugCallback));
|
|
313
343
|
}
|
|
314
344
|
self.audioBuffers = [audioBuffer];
|
|
315
345
|
|
|
@@ -477,6 +507,10 @@ function CreateSynth() {
|
|
|
477
507
|
return downloadBuffer(self);
|
|
478
508
|
};
|
|
479
509
|
|
|
510
|
+
self.getAudioBuffer = function() {
|
|
511
|
+
return self.audioBuffers[0];
|
|
512
|
+
};
|
|
513
|
+
|
|
480
514
|
/////////////// Private functions //////////////
|
|
481
515
|
|
|
482
516
|
self._deviceCapable = function() {
|
|
@@ -506,6 +540,39 @@ function CreateSynth() {
|
|
|
506
540
|
};
|
|
507
541
|
}
|
|
508
542
|
};
|
|
543
|
+
|
|
544
|
+
// // this is a first attempt at adding a little bit of swing to the output, but the algorithm isn't correct.
|
|
545
|
+
// function addSwing(noteMapTracks, swing, beatsPerMeasure) {
|
|
546
|
+
// console.log("addSwing", noteMapTracks, swing, beatsPerMeasure)
|
|
547
|
+
// // Swing should be between -0.9 and 0.9. Make sure the input is between them.
|
|
548
|
+
// // Then that is the percentage to add to the first beat, so a negative number moves the second beat earlier.
|
|
549
|
+
// // A value of zero is the same as no swing at all.
|
|
550
|
+
// // This only works when there are an even number of beats in a measure.
|
|
551
|
+
// if (beatsPerMeasure % 2 !== 0)
|
|
552
|
+
// return;
|
|
553
|
+
// swing = parseFloat(swing)
|
|
554
|
+
// if (isNaN(swing))
|
|
555
|
+
// return
|
|
556
|
+
// if (swing < -0.9)
|
|
557
|
+
// swing = -0.9
|
|
558
|
+
// if (swing > 0.9)
|
|
559
|
+
// swing = 0.9
|
|
560
|
+
// var beatLength = (1 / beatsPerMeasure)*2
|
|
561
|
+
// swing = beatLength * swing
|
|
562
|
+
// for (var t = 0; t < noteMapTracks.length; t++) {
|
|
563
|
+
// var track = noteMapTracks[t];
|
|
564
|
+
// for (var i = 0; i < track.length; i++) {
|
|
565
|
+
// var event = track[i];
|
|
566
|
+
// if (event.start % beatLength) {
|
|
567
|
+
// // This is the off beat
|
|
568
|
+
// event.start += swing;
|
|
569
|
+
// } else {
|
|
570
|
+
// // This is the beat
|
|
571
|
+
// event.end += swing;
|
|
572
|
+
// }
|
|
573
|
+
// }
|
|
574
|
+
// }
|
|
575
|
+
// }
|
|
509
576
|
}
|
|
510
577
|
|
|
511
578
|
module.exports = CreateSynth;
|
package/src/synth/load-note.js
CHANGED
|
@@ -16,7 +16,7 @@ var getNote = function (url, instrument, name, audioContext) {
|
|
|
16
16
|
xhr.responseType = "arraybuffer";
|
|
17
17
|
xhr.onload = function () {
|
|
18
18
|
if (xhr.status !== 200) {
|
|
19
|
-
reject(Error("Can't load sound at " + noteUrl));
|
|
19
|
+
reject(Error("Can't load sound at " + noteUrl + ' status=' + xhr.status));
|
|
20
20
|
return
|
|
21
21
|
}
|
|
22
22
|
var noteDecoded = function(audioBuffer) {
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
var accidentals = {
|
|
2
|
+
"__": -2,
|
|
3
|
+
"_": -1,
|
|
4
|
+
"_/": -0.5,
|
|
5
|
+
"=": 0,
|
|
6
|
+
"": 0,
|
|
7
|
+
"^/": 0.5,
|
|
8
|
+
"^": 1,
|
|
9
|
+
"^^": 2
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
var notesInOrder = ['C', '-', 'D', '-', 'E', 'F', '-', 'G', '-', 'A', '-', 'B', 'c', '-', 'd', '-', 'e', 'f', '-', 'g', '-', 'a', '-', 'b']
|
|
13
|
+
|
|
14
|
+
function noteToMidi(note) {
|
|
15
|
+
var reg = note.match(/([_^\/]*)([ABCDEFGabcdefg])(,*)('*)/)
|
|
16
|
+
if (reg && reg.length === 5) {
|
|
17
|
+
var acc = accidentals[reg[1]]
|
|
18
|
+
var pitch = notesInOrder.indexOf(reg[2])
|
|
19
|
+
var octave = reg[4].length - reg[3].length
|
|
20
|
+
return 48 + pitch + acc + octave * 12;
|
|
21
|
+
}
|
|
22
|
+
return 0;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function midiToNote(midi) {
|
|
26
|
+
midi = parseInt(midi, 10) // TODO-PER: not sure how to handle quarter sharps and flats, so strip them for now.
|
|
27
|
+
var octave = Math.floor(midi / 12)
|
|
28
|
+
var pitch = midi % 12
|
|
29
|
+
var name = notesInOrder[pitch]
|
|
30
|
+
if (name === '-') {
|
|
31
|
+
name = '^' + notesInOrder[pitch-1]
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
if (octave > 4) {
|
|
35
|
+
name = name.toLowerCase()
|
|
36
|
+
octave -= 5
|
|
37
|
+
while (octave > 0) {
|
|
38
|
+
name += "'"
|
|
39
|
+
octave--
|
|
40
|
+
}
|
|
41
|
+
} else {
|
|
42
|
+
while (octave < 4) {
|
|
43
|
+
name += ','
|
|
44
|
+
octave++
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return name
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
module.exports = {noteToMidi: noteToMidi, midiToNote: midiToNote};
|
package/src/synth/place-note.js
CHANGED
|
@@ -2,7 +2,7 @@ var soundsCache = require('./sounds-cache');
|
|
|
2
2
|
var pitchToNoteName = require('./pitch-to-note-name');
|
|
3
3
|
var centsToFactor = require("./cents-to-factor");
|
|
4
4
|
|
|
5
|
-
function placeNote(outputAudioBuffer, sampleRate, sound, startArray, volumeMultiplier, ofsMs, fadeTimeSec, noteEndSec) {
|
|
5
|
+
function placeNote(outputAudioBuffer, sampleRate, sound, startArray, volumeMultiplier, ofsMs, fadeTimeSec, noteEndSec, debugCallback) {
|
|
6
6
|
// sound contains { instrument, pitch, volume, len, pan, tempoMultiplier
|
|
7
7
|
// len is in whole notes. Multiply by tempoMultiplier to get seconds.
|
|
8
8
|
// ofsMs is an offset to subtract from the note to line up programs that have different length onsets.
|
|
@@ -21,6 +21,8 @@ function placeNote(outputAudioBuffer, sampleRate, sound, startArray, volumeMulti
|
|
|
21
21
|
|
|
22
22
|
if (!noteBufferPromise) {
|
|
23
23
|
// if the note isn't present then just skip it - it will leave a blank spot in the audio.
|
|
24
|
+
if (debugCallback)
|
|
25
|
+
debugCallback('placeNote skipped: '+sound.instrument+':'+noteName)
|
|
24
26
|
return Promise.resolve();
|
|
25
27
|
}
|
|
26
28
|
|
|
@@ -81,6 +83,8 @@ function placeNote(outputAudioBuffer, sampleRate, sound, startArray, volumeMulti
|
|
|
81
83
|
copyToChannel(outputAudioBuffer, e.renderedBuffer, start);
|
|
82
84
|
}
|
|
83
85
|
}
|
|
86
|
+
if (debugCallback)
|
|
87
|
+
debugCallback('placeNote: '+sound.instrument+':'+noteName)
|
|
84
88
|
fnResolve();
|
|
85
89
|
};
|
|
86
90
|
offlineCtx.startRendering();
|
|
@@ -88,7 +92,11 @@ function placeNote(outputAudioBuffer, sampleRate, sound, startArray, volumeMulti
|
|
|
88
92
|
fnResolve = resolve;
|
|
89
93
|
});
|
|
90
94
|
})
|
|
91
|
-
.catch(function () {
|
|
95
|
+
.catch(function (error) {
|
|
96
|
+
if (debugCallback)
|
|
97
|
+
debugCallback('placeNote catch: '+error.message)
|
|
98
|
+
return Promise.resolve()
|
|
99
|
+
});
|
|
92
100
|
}
|
|
93
101
|
|
|
94
102
|
var copyToChannel = function(toBuffer, fromBuffer, start) {
|
|
@@ -5,7 +5,6 @@ var StringTablature = require('../string-tablature');
|
|
|
5
5
|
var TabCommon = require('../../tab-common');
|
|
6
6
|
var TabRenderer = require('../../tab-renderer');
|
|
7
7
|
var GuitarPatterns = require('./guitar-patterns');
|
|
8
|
-
var setGuitarFonts = require('./guitar-fonts');
|
|
9
8
|
|
|
10
9
|
/**
|
|
11
10
|
* upon init mainly store provided instances for later usage
|
|
@@ -32,7 +31,6 @@ Plugin.prototype.init = function (abcTune, tuneNumber, params) {
|
|
|
32
31
|
Plugin.prototype.render = function (renderer, line, staffIndex) {
|
|
33
32
|
if (this._super.inError) return;
|
|
34
33
|
if (this.tablature.bypass(line)) return;
|
|
35
|
-
setGuitarFonts(this.abcTune);
|
|
36
34
|
var rndrer = new TabRenderer(this, renderer, line, staffIndex);
|
|
37
35
|
rndrer.doLayout();
|
|
38
36
|
};
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
const {noteToMidi} = require('../../synth/note-to-midi');
|
|
1
2
|
var TabNote = require('./tab-note');
|
|
2
3
|
var TabNotes = require('./tab-notes');
|
|
3
4
|
|
|
@@ -93,7 +94,10 @@ function sameString(self, chord) {
|
|
|
93
94
|
function handleChordNotes(self, notes) {
|
|
94
95
|
var retNotes = [];
|
|
95
96
|
for (var iiii = 0; iiii < notes.length; iiii++) {
|
|
96
|
-
|
|
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)
|
|
97
101
|
var curPos = toNumber(self, note);
|
|
98
102
|
retNotes.push(curPos);
|
|
99
103
|
}
|
|
@@ -147,26 +151,23 @@ function toNumber(self, note) {
|
|
|
147
151
|
acc = "="
|
|
148
152
|
self.measureAccidentals[note.name.toUpperCase()] = acc
|
|
149
153
|
}
|
|
150
|
-
var
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
};
|
|
161
|
-
}
|
|
162
|
-
while (str < self.strings.length) {
|
|
163
|
-
num = noteToNumber(self, note, str);
|
|
164
|
-
if (num) {
|
|
165
|
-
return num;
|
|
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
|
+
}
|
|
166
164
|
}
|
|
167
|
-
str++;
|
|
168
165
|
}
|
|
169
|
-
return
|
|
166
|
+
return {
|
|
167
|
+
num: "?",
|
|
168
|
+
str: self.stringPitches.length-1,
|
|
169
|
+
note: note,
|
|
170
|
+
};
|
|
170
171
|
}
|
|
171
172
|
|
|
172
173
|
StringPatterns.prototype.stringToPitch = function (stringNumber) {
|
|
@@ -198,13 +199,16 @@ StringPatterns.prototype.notesToNumber = function (notes, graces) {
|
|
|
198
199
|
error = retNotes.error;
|
|
199
200
|
}
|
|
200
201
|
} else {
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
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
|
+
}
|
|
208
212
|
}
|
|
209
213
|
}
|
|
210
214
|
}
|
|
@@ -213,7 +217,8 @@ StringPatterns.prototype.notesToNumber = function (notes, graces) {
|
|
|
213
217
|
if (graces) {
|
|
214
218
|
retGraces = [];
|
|
215
219
|
for (var iiii = 0; iiii < graces.length; iiii++) {
|
|
216
|
-
note = new TabNote.TabNote(graces[iiii].name);
|
|
220
|
+
note = new TabNote.TabNote(graces[iiii].name, this.clefTranspose);
|
|
221
|
+
note.checkKeyAccidentals(this.accidentals, this.measureAccidentals)
|
|
217
222
|
number = toNumber(this, note);
|
|
218
223
|
if (number) {
|
|
219
224
|
retGraces.push(number);
|
|
@@ -232,7 +237,14 @@ StringPatterns.prototype.notesToNumber = function (notes, graces) {
|
|
|
232
237
|
};
|
|
233
238
|
|
|
234
239
|
StringPatterns.prototype.toString = function () {
|
|
235
|
-
|
|
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('');
|
|
236
248
|
};
|
|
237
249
|
|
|
238
250
|
StringPatterns.prototype.tabInfos = function (plugin) {
|
|
@@ -273,9 +285,15 @@ function StringPatterns(plugin) {
|
|
|
273
285
|
this.measureAccidentals = {}
|
|
274
286
|
this.capo = 0;
|
|
275
287
|
if (capo) {
|
|
276
|
-
this.capo = capo;
|
|
288
|
+
this.capo = parseInt(capo,10);
|
|
277
289
|
}
|
|
290
|
+
this.transpose = plugin.transpose ? plugin.transpose : 0
|
|
278
291
|
this.tuning = tuning;
|
|
292
|
+
this.stringPitches = []
|
|
293
|
+
for (var i = 0; i < this.tuning.length; i++) {
|
|
294
|
+
var pitch = noteToMidi(this.tuning[i]) + this.capo
|
|
295
|
+
this.stringPitches.push(pitch)
|
|
296
|
+
}
|
|
279
297
|
if (this.capo > 0) {
|
|
280
298
|
this.capoTuning = buildCapo(this);
|
|
281
299
|
}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
var {noteToMidi, midiToNote} = require('../../synth/note-to-midi');
|
|
2
|
+
|
|
1
3
|
/**
|
|
2
4
|
*
|
|
3
5
|
* Note structure for Tabs
|
|
@@ -6,9 +8,12 @@
|
|
|
6
8
|
var notes = ['A', 'B', 'C', 'D', 'E', 'F', 'G'];
|
|
7
9
|
|
|
8
10
|
|
|
9
|
-
function TabNote(note) {
|
|
11
|
+
function TabNote(note, clefTranspose) {
|
|
12
|
+
var pitch = noteToMidi(note)
|
|
13
|
+
if (clefTranspose)
|
|
14
|
+
pitch += clefTranspose
|
|
15
|
+
var newNote = midiToNote(pitch);
|
|
10
16
|
var isFlat = false;
|
|
11
|
-
var newNote = note;
|
|
12
17
|
var isSharp = false;
|
|
13
18
|
var isAltered = false;
|
|
14
19
|
var natural = null;
|
|
@@ -54,9 +59,11 @@ function TabNote(note) {
|
|
|
54
59
|
newNote = note.slice(1);
|
|
55
60
|
}
|
|
56
61
|
}
|
|
57
|
-
var hasComma = (
|
|
58
|
-
var hasQuote = (
|
|
62
|
+
var hasComma = (newNote.match(/,/g) || []).length;
|
|
63
|
+
var hasQuote = (newNote.match(/'/g) || []).length;
|
|
59
64
|
|
|
65
|
+
this.pitch = pitch
|
|
66
|
+
this.pitchAltered = 0
|
|
60
67
|
this.name = newNote;
|
|
61
68
|
this.acc = acc;
|
|
62
69
|
this.isSharp = isSharp;
|
|
@@ -76,6 +83,7 @@ function TabNote(note) {
|
|
|
76
83
|
function cloneNote(self) {
|
|
77
84
|
var newNote = self.name;
|
|
78
85
|
var newTabNote = new TabNote(newNote);
|
|
86
|
+
newTabNote.pitch = self.pitch;
|
|
79
87
|
newTabNote.hasComma = self.hasComma;
|
|
80
88
|
newTabNote.isLower = self.isLower;
|
|
81
89
|
newTabNote.isQuoted = self.isQuoted;
|
|
@@ -86,33 +94,11 @@ function cloneNote(self) {
|
|
|
86
94
|
return newTabNote;
|
|
87
95
|
}
|
|
88
96
|
TabNote.prototype.sameNoteAs = function (note) {
|
|
89
|
-
|
|
90
|
-
(this.hasComma == note.hasComma) &&
|
|
91
|
-
(this.isLower == note.isLower) &&
|
|
92
|
-
(this.isQuoted == note.isQuoted) &&
|
|
93
|
-
(this.isSharp == note.isSharp) &&
|
|
94
|
-
(this.isFlat == note.isFlat)) {
|
|
95
|
-
return true;
|
|
96
|
-
} else {
|
|
97
|
-
return false;
|
|
98
|
-
}
|
|
97
|
+
return note.pitch === this.pitch
|
|
99
98
|
};
|
|
100
99
|
|
|
101
100
|
TabNote.prototype.isLowerThan = function (note) {
|
|
102
|
-
|
|
103
|
-
if (this.hasComma > note.hasComma) return true;
|
|
104
|
-
if (note.hasComma > this.hasComma) return false;
|
|
105
|
-
if (this.isQuoted > note.isQuoted) return false;
|
|
106
|
-
if (note.isQuoted > this.isQuoted) return true;
|
|
107
|
-
if (this.isLower) {
|
|
108
|
-
if (!note.isLower) return false;
|
|
109
|
-
} else {
|
|
110
|
-
if (note.isLower) return true;
|
|
111
|
-
}
|
|
112
|
-
var noteName = note.name[0].toUpperCase();
|
|
113
|
-
var thisName = this.name[0].toUpperCase();
|
|
114
|
-
if (noteComparator.indexOf(thisName) < noteComparator.indexOf(noteName)) return true;
|
|
115
|
-
return false;
|
|
101
|
+
return note.pitch > this.pitch
|
|
116
102
|
};
|
|
117
103
|
|
|
118
104
|
TabNote.prototype.checkKeyAccidentals = function(accidentals, measureAccidentals) {
|
|
@@ -120,14 +106,13 @@ TabNote.prototype.checkKeyAccidentals = function(accidentals, measureAccidentals
|
|
|
120
106
|
return
|
|
121
107
|
if (measureAccidentals[this.name.toUpperCase()]) {
|
|
122
108
|
switch (measureAccidentals[this.name.toUpperCase()]) {
|
|
123
|
-
case "__": this.acc = -2; return;
|
|
124
|
-
case "_": this.acc = -1; return;
|
|
125
|
-
case "=": this.acc = 0; return;
|
|
126
|
-
case "^": this.acc = 1; return;
|
|
127
|
-
case "^^": this.acc = 2; return;
|
|
109
|
+
case "__": this.acc = -2; this.pitchAltered = -2; return;
|
|
110
|
+
case "_": this.acc = -1; this.pitchAltered = -1; return;
|
|
111
|
+
case "=": this.acc = 0; this.pitchAltered = 0; return;
|
|
112
|
+
case "^": this.acc = 1; this.pitchAltered = 1; return;
|
|
113
|
+
case "^^": this.acc = 2; this.pitchAltered = 2; return;
|
|
128
114
|
}
|
|
129
|
-
}
|
|
130
|
-
if (accidentals) {
|
|
115
|
+
} else if (accidentals) {
|
|
131
116
|
var curNote = this.name;
|
|
132
117
|
for (var iii = 0; iii < accidentals.length; iii++) {
|
|
133
118
|
var curAccidentals = accidentals[iii];
|
|
@@ -135,10 +120,12 @@ TabNote.prototype.checkKeyAccidentals = function(accidentals, measureAccidentals
|
|
|
135
120
|
if (curAccidentals.acc == 'flat') {
|
|
136
121
|
this.acc = -1;
|
|
137
122
|
this.isKeyFlat = true;
|
|
123
|
+
this.pitchAltered = -1
|
|
138
124
|
}
|
|
139
125
|
if (curAccidentals.acc == 'sharp') {
|
|
140
126
|
this.acc = +1;
|
|
141
127
|
this.isKeySharp = true;
|
|
128
|
+
this.pitchAltered = 1
|
|
142
129
|
}
|
|
143
130
|
}
|
|
144
131
|
}
|
|
@@ -163,77 +150,13 @@ TabNote.prototype.getAccidentalEquiv = function () {
|
|
|
163
150
|
|
|
164
151
|
|
|
165
152
|
TabNote.prototype.nextNote = function () {
|
|
166
|
-
var
|
|
167
|
-
|
|
168
|
-
if (!this.isSharp && !this.isKeySharp ) {
|
|
169
|
-
if (this.name != 'E' && this.name != 'B') {
|
|
170
|
-
newTabNote.isSharp = true;
|
|
171
|
-
return newTabNote;
|
|
172
|
-
}
|
|
173
|
-
} else {
|
|
174
|
-
// cleanup
|
|
175
|
-
newTabNote.isSharp = false;
|
|
176
|
-
newTabNote.isKeySharp = false;
|
|
177
|
-
}
|
|
178
|
-
var noteIndex = notes.indexOf(this.name);
|
|
179
|
-
if (noteIndex == notes.length - 1) {
|
|
180
|
-
noteIndex = 0;
|
|
181
|
-
} else {
|
|
182
|
-
noteIndex++;
|
|
183
|
-
}
|
|
184
|
-
newTabNote.name = notes[noteIndex];
|
|
185
|
-
if (newTabNote.name == 'C') {
|
|
186
|
-
if (newTabNote.hasComma > 0) {
|
|
187
|
-
newTabNote.hasComma--;
|
|
188
|
-
} else {
|
|
189
|
-
if (!newTabNote.isLower) {
|
|
190
|
-
newTabNote.isLower = true;
|
|
191
|
-
} else {
|
|
192
|
-
newTabNote.isQuoted = true;
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
return newTabNote;
|
|
153
|
+
var note = midiToNote(this.pitch+1+this.pitchAltered)
|
|
154
|
+
return new TabNote(note)
|
|
197
155
|
};
|
|
198
156
|
|
|
199
157
|
TabNote.prototype.prevNote = function () {
|
|
200
|
-
var
|
|
201
|
-
|
|
202
|
-
if (this.isSharp) {
|
|
203
|
-
newTabNote.isSharp = false;
|
|
204
|
-
return newTabNote;
|
|
205
|
-
}
|
|
206
|
-
var noteIndex = notes.indexOf(this.name);
|
|
207
|
-
if (noteIndex == 0) {
|
|
208
|
-
noteIndex = notes.length - 1;
|
|
209
|
-
} else {
|
|
210
|
-
noteIndex--;
|
|
211
|
-
}
|
|
212
|
-
newTabNote.name = notes[noteIndex];
|
|
213
|
-
if (newTabNote.name == 'B') {
|
|
214
|
-
if (newTabNote.isLower) {
|
|
215
|
-
newTabNote.hasComma = 1;
|
|
216
|
-
} else {
|
|
217
|
-
if (newTabNote.hasComma > 0) {
|
|
218
|
-
newTabNote.hasComma++;
|
|
219
|
-
} else {
|
|
220
|
-
if (newTabNote.isQuoted > 0) {
|
|
221
|
-
newTabNote.isQuoted -= 1;
|
|
222
|
-
} else {
|
|
223
|
-
newTabNote.isLower = true;
|
|
224
|
-
}
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
if (this.isFlat) {
|
|
229
|
-
newTabNote.isFlat = false;
|
|
230
|
-
return newTabNote;
|
|
231
|
-
} else {
|
|
232
|
-
if (this.name != 'E' && this.name != 'B') {
|
|
233
|
-
newTabNote.isSharp = true;
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
return newTabNote;
|
|
158
|
+
var note = midiToNote(this.pitch-1+this.pitchAltered)
|
|
159
|
+
return new TabNote(note)
|
|
237
160
|
};
|
|
238
161
|
|
|
239
162
|
TabNote.prototype.emitNoAccidentals = function ( ) {
|
|
@@ -3,7 +3,6 @@ var StringTablature = require('../string-tablature');
|
|
|
3
3
|
var TabCommon = require('../../tab-common');
|
|
4
4
|
var TabRenderer = require('../../tab-renderer');
|
|
5
5
|
var ViolinPatterns = require('./violin-patterns');
|
|
6
|
-
var setViolinFonts = require('./violin-fonts');
|
|
7
6
|
|
|
8
7
|
|
|
9
8
|
/**
|
|
@@ -30,7 +29,6 @@ Plugin.prototype.init = function (abcTune, tuneNumber, params) {
|
|
|
30
29
|
Plugin.prototype.render = function (renderer, line, staffIndex) {
|
|
31
30
|
if (this._super.inError) return;
|
|
32
31
|
if (this.tablature.bypass(line)) return;
|
|
33
|
-
setViolinFonts(this.abcTune);
|
|
34
32
|
var rndrer = new TabRenderer(this, renderer, line, staffIndex);
|
|
35
33
|
rndrer.doLayout();
|
|
36
34
|
};
|