@coderline/alphatab 1.8.0 → 1.8.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/dist/alphaTab.core.min.mjs +2 -2
- package/dist/alphaTab.core.mjs +618 -355
- package/dist/alphaTab.d.ts +131 -4
- package/dist/alphaTab.js +618 -355
- package/dist/alphaTab.min.js +2 -2
- package/dist/alphaTab.min.mjs +1 -1
- package/dist/alphaTab.mjs +1 -1
- package/dist/alphaTab.worker.min.mjs +1 -1
- package/dist/alphaTab.worker.mjs +1 -1
- package/dist/alphaTab.worklet.min.mjs +1 -1
- package/dist/alphaTab.worklet.mjs +1 -1
- package/package.json +1 -1
package/dist/alphaTab.core.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* alphaTab v1.8.
|
|
2
|
+
* alphaTab v1.8.1 (, build 30)
|
|
3
3
|
*
|
|
4
4
|
* Copyright © 2026, Daniel Kuschny and Contributors, All rights reserved.
|
|
5
5
|
*
|
|
@@ -203,9 +203,9 @@ class AlphaTabError extends Error {
|
|
|
203
203
|
* @internal
|
|
204
204
|
*/
|
|
205
205
|
class VersionInfo {
|
|
206
|
-
static version = '1.8.
|
|
207
|
-
static date = '2026-
|
|
208
|
-
static commit = '
|
|
206
|
+
static version = '1.8.1';
|
|
207
|
+
static date = '2026-02-01T19:53:46.853Z';
|
|
208
|
+
static commit = '8a2102fe7ee7dcf4b50c3a4198fbb8c0d5c0fda3';
|
|
209
209
|
static print(print) {
|
|
210
210
|
print(`alphaTab ${VersionInfo.version}`);
|
|
211
211
|
print(`commit: ${VersionInfo.commit}`);
|
|
@@ -4519,135 +4519,6 @@ class ModelUtils {
|
|
|
4519
4519
|
return ModelUtils._keyTransposeTable[transpose][keySignature + 7];
|
|
4520
4520
|
}
|
|
4521
4521
|
}
|
|
4522
|
-
/**
|
|
4523
|
-
* a lookup list containing an info whether the notes within an octave
|
|
4524
|
-
* need an accidental rendered. the accidental symbol is determined based on the type of key signature.
|
|
4525
|
-
*/
|
|
4526
|
-
static _keySignatureLookup = [
|
|
4527
|
-
// Flats (where the value is true, a flat accidental is required for the notes)
|
|
4528
|
-
[true, true, true, true, true, true, true, true, true, true, true, true],
|
|
4529
|
-
[true, true, true, true, true, false, true, true, true, true, true, true],
|
|
4530
|
-
[false, true, true, true, true, false, true, true, true, true, true, true],
|
|
4531
|
-
[false, true, true, true, true, false, false, false, true, true, true, true],
|
|
4532
|
-
[false, false, false, true, true, false, false, false, true, true, true, true],
|
|
4533
|
-
[false, false, false, true, true, false, false, false, false, false, true, true],
|
|
4534
|
-
[false, false, false, false, false, false, false, false, false, false, true, true],
|
|
4535
|
-
// natural
|
|
4536
|
-
[false, false, false, false, false, false, false, false, false, false, false, false],
|
|
4537
|
-
// sharps (where the value is true, a flat accidental is required for the notes)
|
|
4538
|
-
[false, false, false, false, false, true, true, false, false, false, false, false],
|
|
4539
|
-
[true, true, false, false, false, true, true, false, false, false, false, false],
|
|
4540
|
-
[true, true, false, false, false, true, true, true, true, false, false, false],
|
|
4541
|
-
[true, true, true, true, false, true, true, true, true, false, false, false],
|
|
4542
|
-
[true, true, true, true, false, true, true, true, true, true, true, false],
|
|
4543
|
-
[true, true, true, true, true, true, true, true, true, true, true, false],
|
|
4544
|
-
[true, true, true, true, true, true, true, true, true, true, true, true]
|
|
4545
|
-
];
|
|
4546
|
-
/**
|
|
4547
|
-
* Contains the list of notes within an octave have accidentals set.
|
|
4548
|
-
* @internal
|
|
4549
|
-
*/
|
|
4550
|
-
static accidentalNotes = [
|
|
4551
|
-
false,
|
|
4552
|
-
true,
|
|
4553
|
-
false,
|
|
4554
|
-
true,
|
|
4555
|
-
false,
|
|
4556
|
-
false,
|
|
4557
|
-
true,
|
|
4558
|
-
false,
|
|
4559
|
-
true,
|
|
4560
|
-
false,
|
|
4561
|
-
true,
|
|
4562
|
-
false
|
|
4563
|
-
];
|
|
4564
|
-
/**
|
|
4565
|
-
* @internal
|
|
4566
|
-
*/
|
|
4567
|
-
static computeAccidental(keySignature, accidentalMode, noteValue, quarterBend, currentAccidental = null) {
|
|
4568
|
-
const ks = keySignature;
|
|
4569
|
-
const ksi = ks + 7;
|
|
4570
|
-
const index = noteValue % 12;
|
|
4571
|
-
const accidentalForKeySignature = ksi < 7 ? AccidentalType.Flat : AccidentalType.Sharp;
|
|
4572
|
-
const hasKeySignatureAccidentalSetForNote = ModelUtils._keySignatureLookup[ksi][index];
|
|
4573
|
-
const hasNoteAccidentalWithinOctave = ModelUtils.accidentalNotes[index];
|
|
4574
|
-
// the general logic is like this:
|
|
4575
|
-
// - we check if the key signature has an accidental defined
|
|
4576
|
-
// - we calculate which accidental a note needs according to its index in the octave
|
|
4577
|
-
// - if the accidental is already placed at this line, nothing needs to be done, otherwise we place it
|
|
4578
|
-
// - if there should not be an accidental, but there is one in the key signature, we clear it.
|
|
4579
|
-
// the exceptions are:
|
|
4580
|
-
// - for quarter bends we just place the corresponding accidental
|
|
4581
|
-
// - the accidental mode can enforce the accidentals for the note
|
|
4582
|
-
let accidentalToSet = AccidentalType.None;
|
|
4583
|
-
if (quarterBend) {
|
|
4584
|
-
accidentalToSet = hasNoteAccidentalWithinOctave ? accidentalForKeySignature : AccidentalType.Natural;
|
|
4585
|
-
switch (accidentalToSet) {
|
|
4586
|
-
case AccidentalType.Natural:
|
|
4587
|
-
accidentalToSet = AccidentalType.NaturalQuarterNoteUp;
|
|
4588
|
-
break;
|
|
4589
|
-
case AccidentalType.Sharp:
|
|
4590
|
-
accidentalToSet = AccidentalType.SharpQuarterNoteUp;
|
|
4591
|
-
break;
|
|
4592
|
-
case AccidentalType.Flat:
|
|
4593
|
-
accidentalToSet = AccidentalType.FlatQuarterNoteUp;
|
|
4594
|
-
break;
|
|
4595
|
-
}
|
|
4596
|
-
}
|
|
4597
|
-
else {
|
|
4598
|
-
// define which accidental should be shown ignoring what might be set on the KS already
|
|
4599
|
-
switch (accidentalMode) {
|
|
4600
|
-
case NoteAccidentalMode.ForceSharp:
|
|
4601
|
-
accidentalToSet = AccidentalType.Sharp;
|
|
4602
|
-
break;
|
|
4603
|
-
case NoteAccidentalMode.ForceDoubleSharp:
|
|
4604
|
-
accidentalToSet = AccidentalType.DoubleSharp;
|
|
4605
|
-
break;
|
|
4606
|
-
case NoteAccidentalMode.ForceFlat:
|
|
4607
|
-
accidentalToSet = AccidentalType.Flat;
|
|
4608
|
-
break;
|
|
4609
|
-
case NoteAccidentalMode.ForceDoubleFlat:
|
|
4610
|
-
accidentalToSet = AccidentalType.DoubleFlat;
|
|
4611
|
-
break;
|
|
4612
|
-
default:
|
|
4613
|
-
// if note has an accidental in the octave, we place a symbol
|
|
4614
|
-
// according to the Key Signature
|
|
4615
|
-
if (hasNoteAccidentalWithinOctave) {
|
|
4616
|
-
accidentalToSet = accidentalForKeySignature;
|
|
4617
|
-
}
|
|
4618
|
-
else if (hasKeySignatureAccidentalSetForNote) {
|
|
4619
|
-
// note does not get an accidental, but KS defines one -> Naturalize
|
|
4620
|
-
accidentalToSet = AccidentalType.Natural;
|
|
4621
|
-
}
|
|
4622
|
-
break;
|
|
4623
|
-
}
|
|
4624
|
-
// do we need an accidental on the note?
|
|
4625
|
-
if (accidentalToSet !== AccidentalType.None) {
|
|
4626
|
-
// if there is no accidental on the line, and the key signature has it set already, we clear it on the note
|
|
4627
|
-
if (currentAccidental != null) {
|
|
4628
|
-
if (currentAccidental === accidentalToSet) {
|
|
4629
|
-
accidentalToSet = AccidentalType.None;
|
|
4630
|
-
}
|
|
4631
|
-
}
|
|
4632
|
-
else if (hasKeySignatureAccidentalSetForNote && accidentalToSet === accidentalForKeySignature) {
|
|
4633
|
-
accidentalToSet = AccidentalType.None;
|
|
4634
|
-
}
|
|
4635
|
-
}
|
|
4636
|
-
else {
|
|
4637
|
-
// if we don't want an accidental, but there is already one applied, we place a naturalize accidental
|
|
4638
|
-
// and clear the registration
|
|
4639
|
-
if (currentAccidental !== null) {
|
|
4640
|
-
if (currentAccidental === AccidentalType.Natural) {
|
|
4641
|
-
accidentalToSet = AccidentalType.None;
|
|
4642
|
-
}
|
|
4643
|
-
else {
|
|
4644
|
-
accidentalToSet = AccidentalType.Natural;
|
|
4645
|
-
}
|
|
4646
|
-
}
|
|
4647
|
-
}
|
|
4648
|
-
}
|
|
4649
|
-
return accidentalToSet;
|
|
4650
|
-
}
|
|
4651
4522
|
/**
|
|
4652
4523
|
* @internal
|
|
4653
4524
|
*/
|
|
@@ -4686,6 +4557,239 @@ class ModelUtils {
|
|
|
4686
4557
|
}
|
|
4687
4558
|
return systemIndex < systemsLayout.length ? systemsLayout[systemIndex] : defaultSystemsLayout;
|
|
4688
4559
|
}
|
|
4560
|
+
// diatonic accidentals
|
|
4561
|
+
static _degreeSemitones = [0, 2, 4, 5, 7, 9, 11];
|
|
4562
|
+
static _sharpPreferredSpellings = [
|
|
4563
|
+
{ degree: 0, accidentalOffset: 0 }, // C
|
|
4564
|
+
{ degree: 0, accidentalOffset: 1 }, // C#
|
|
4565
|
+
{ degree: 1, accidentalOffset: 0 }, // D
|
|
4566
|
+
{ degree: 1, accidentalOffset: 1 }, // D#
|
|
4567
|
+
{ degree: 2, accidentalOffset: 0 }, // E
|
|
4568
|
+
{ degree: 3, accidentalOffset: 0 }, // F
|
|
4569
|
+
{ degree: 3, accidentalOffset: 1 }, // F#
|
|
4570
|
+
{ degree: 4, accidentalOffset: 0 }, // G
|
|
4571
|
+
{ degree: 4, accidentalOffset: 1 }, // G#
|
|
4572
|
+
{ degree: 5, accidentalOffset: 0 }, // A
|
|
4573
|
+
{ degree: 5, accidentalOffset: 1 }, // A#
|
|
4574
|
+
{ degree: 6, accidentalOffset: 0 } // B
|
|
4575
|
+
];
|
|
4576
|
+
static _flatPreferredSpellings = [
|
|
4577
|
+
{ degree: 0, accidentalOffset: 0 }, // C
|
|
4578
|
+
{ degree: 1, accidentalOffset: -1 }, // Db
|
|
4579
|
+
{ degree: 1, accidentalOffset: 0 }, // D
|
|
4580
|
+
{ degree: 2, accidentalOffset: -1 }, // Eb
|
|
4581
|
+
{ degree: 2, accidentalOffset: 0 }, // E
|
|
4582
|
+
{ degree: 3, accidentalOffset: 0 }, // F
|
|
4583
|
+
{ degree: 4, accidentalOffset: -1 }, // Gb
|
|
4584
|
+
{ degree: 4, accidentalOffset: 0 }, // G
|
|
4585
|
+
{ degree: 5, accidentalOffset: -1 }, // Ab
|
|
4586
|
+
{ degree: 5, accidentalOffset: 0 }, // A
|
|
4587
|
+
{ degree: 6, accidentalOffset: -1 }, // Bb
|
|
4588
|
+
{ degree: 6, accidentalOffset: 0 } // B
|
|
4589
|
+
];
|
|
4590
|
+
// 12 chromatic pitch classes with always 3 possible spellings in the
|
|
4591
|
+
// accidental range of bb..##
|
|
4592
|
+
static _spellingCandidates = [
|
|
4593
|
+
// 0: C
|
|
4594
|
+
[
|
|
4595
|
+
{ degree: 0, accidentalOffset: 0 }, // C
|
|
4596
|
+
{ degree: 1, accidentalOffset: -2 }, // Dbb
|
|
4597
|
+
{ degree: 6, accidentalOffset: 1 } // B#
|
|
4598
|
+
],
|
|
4599
|
+
// 1: C#/Db
|
|
4600
|
+
[
|
|
4601
|
+
{ degree: 0, accidentalOffset: 1 }, // C#
|
|
4602
|
+
{ degree: 1, accidentalOffset: -1 }, // Db
|
|
4603
|
+
{ degree: 6, accidentalOffset: 2 } // B##
|
|
4604
|
+
],
|
|
4605
|
+
// 2: D
|
|
4606
|
+
[
|
|
4607
|
+
{ degree: 1, accidentalOffset: 0 }, // D
|
|
4608
|
+
{ degree: 0, accidentalOffset: 2 }, // C##
|
|
4609
|
+
{ degree: 2, accidentalOffset: -2 } // Ebb
|
|
4610
|
+
],
|
|
4611
|
+
// 3: D#/Eb
|
|
4612
|
+
[
|
|
4613
|
+
{ degree: 1, accidentalOffset: 1 }, // D#
|
|
4614
|
+
{ degree: 2, accidentalOffset: -1 }, // Eb
|
|
4615
|
+
{ degree: 3, accidentalOffset: -2 } // Fbb
|
|
4616
|
+
],
|
|
4617
|
+
// 4: E
|
|
4618
|
+
[
|
|
4619
|
+
{ degree: 2, accidentalOffset: 0 }, // E
|
|
4620
|
+
{ degree: 1, accidentalOffset: 2 }, // D##
|
|
4621
|
+
{ degree: 3, accidentalOffset: -1 } // Fb
|
|
4622
|
+
],
|
|
4623
|
+
// 5: F
|
|
4624
|
+
[
|
|
4625
|
+
{ degree: 3, accidentalOffset: 0 }, // F
|
|
4626
|
+
{ degree: 2, accidentalOffset: 1 }, // E#
|
|
4627
|
+
{ degree: 4, accidentalOffset: -2 } // Gbb
|
|
4628
|
+
],
|
|
4629
|
+
// 6: F#/Gb
|
|
4630
|
+
[
|
|
4631
|
+
{ degree: 3, accidentalOffset: 1 }, // F#
|
|
4632
|
+
{ degree: 4, accidentalOffset: -1 }, // Gb
|
|
4633
|
+
{ degree: 2, accidentalOffset: 2 } // E##
|
|
4634
|
+
],
|
|
4635
|
+
// 7: G
|
|
4636
|
+
[
|
|
4637
|
+
{ degree: 4, accidentalOffset: 0 }, // G
|
|
4638
|
+
{ degree: 3, accidentalOffset: 2 }, // F##
|
|
4639
|
+
{ degree: 5, accidentalOffset: -2 } // Abb
|
|
4640
|
+
],
|
|
4641
|
+
// 8: G#/Ab
|
|
4642
|
+
[
|
|
4643
|
+
{ degree: 4, accidentalOffset: 1 }, // G#
|
|
4644
|
+
{ degree: 5, accidentalOffset: -1 } // Ab
|
|
4645
|
+
],
|
|
4646
|
+
// 9: A
|
|
4647
|
+
[
|
|
4648
|
+
{ degree: 5, accidentalOffset: 0 }, // A
|
|
4649
|
+
{ degree: 4, accidentalOffset: 2 }, // G##
|
|
4650
|
+
{ degree: 6, accidentalOffset: -2 } // Bbb
|
|
4651
|
+
],
|
|
4652
|
+
// 10: A#/Bb
|
|
4653
|
+
[
|
|
4654
|
+
{ degree: 5, accidentalOffset: 1 }, // A#
|
|
4655
|
+
{ degree: 6, accidentalOffset: -1 }, // Bb
|
|
4656
|
+
{ degree: 0, accidentalOffset: -2 } // Cbb
|
|
4657
|
+
],
|
|
4658
|
+
// 11: B
|
|
4659
|
+
[
|
|
4660
|
+
{ degree: 6, accidentalOffset: 0 }, // B
|
|
4661
|
+
{ degree: 5, accidentalOffset: 2 }, // A##
|
|
4662
|
+
{ degree: 0, accidentalOffset: -1 } // Cb
|
|
4663
|
+
]
|
|
4664
|
+
];
|
|
4665
|
+
static _sharpKeySignatureOrder = [3, 0, 4, 1, 5, 2, 6]; // F C G D A E B
|
|
4666
|
+
static _flatKeySignatureOrder = [6, 2, 5, 1, 4, 0, 3]; // B E A D G C F
|
|
4667
|
+
static _keySignatureAccidentalByDegree = ModelUtils._buildKeySignatureAccidentalByDegree();
|
|
4668
|
+
static _accidentalOffsetToType = new Map([
|
|
4669
|
+
[-2, AccidentalType.DoubleFlat],
|
|
4670
|
+
[-1, AccidentalType.Flat],
|
|
4671
|
+
[0, AccidentalType.Natural],
|
|
4672
|
+
[1, AccidentalType.Sharp],
|
|
4673
|
+
[2, AccidentalType.DoubleSharp]
|
|
4674
|
+
]);
|
|
4675
|
+
static _forcedAccidentalOffsetByMode = new Map([
|
|
4676
|
+
[NoteAccidentalMode.ForceSharp, 1],
|
|
4677
|
+
[NoteAccidentalMode.ForceDoubleSharp, 2],
|
|
4678
|
+
[NoteAccidentalMode.ForceFlat, -1],
|
|
4679
|
+
[NoteAccidentalMode.ForceDoubleFlat, -2],
|
|
4680
|
+
[NoteAccidentalMode.ForceNatural, 0],
|
|
4681
|
+
[NoteAccidentalMode.ForceNone, 0],
|
|
4682
|
+
[NoteAccidentalMode.Default, Number.NaN]
|
|
4683
|
+
]);
|
|
4684
|
+
static _buildKeySignatureAccidentalByDegree() {
|
|
4685
|
+
const lookup = [];
|
|
4686
|
+
for (let ks = -7; ks <= 7; ks++) {
|
|
4687
|
+
const row = [0, 0, 0, 0, 0, 0, 0];
|
|
4688
|
+
if (ks > 0) {
|
|
4689
|
+
for (let i = 0; i < ks; i++) {
|
|
4690
|
+
row[ModelUtils._sharpKeySignatureOrder[i]] = 1;
|
|
4691
|
+
}
|
|
4692
|
+
}
|
|
4693
|
+
else if (ks < 0) {
|
|
4694
|
+
for (let i = 0; i < -ks; i++) {
|
|
4695
|
+
row[ModelUtils._flatKeySignatureOrder[i]] = -1;
|
|
4696
|
+
}
|
|
4697
|
+
}
|
|
4698
|
+
lookup.push(row);
|
|
4699
|
+
}
|
|
4700
|
+
return lookup;
|
|
4701
|
+
}
|
|
4702
|
+
static getKeySignatureAccidentalOffset(keySignature, degree) {
|
|
4703
|
+
return ModelUtils._keySignatureAccidentalByDegree[keySignature + 7][degree];
|
|
4704
|
+
}
|
|
4705
|
+
static resolveSpelling(keySignature, noteValue, accidentalMode) {
|
|
4706
|
+
const chroma = ModelUtils.flooredDivision(noteValue, 12);
|
|
4707
|
+
const preferred = ModelUtils._getPreferredSpellingForKeySignature(keySignature, chroma);
|
|
4708
|
+
const desiredOffset = ModelUtils._forcedAccidentalOffsetByMode.has(accidentalMode)
|
|
4709
|
+
? ModelUtils._forcedAccidentalOffsetByMode.get(accidentalMode)
|
|
4710
|
+
: Number.NaN;
|
|
4711
|
+
let spelling = preferred;
|
|
4712
|
+
if (!Number.isNaN(desiredOffset)) {
|
|
4713
|
+
const candidates = ModelUtils._spellingCandidates[chroma];
|
|
4714
|
+
const exact = candidates.find(c => c.accidentalOffset === desiredOffset);
|
|
4715
|
+
if (exact) {
|
|
4716
|
+
spelling = exact;
|
|
4717
|
+
}
|
|
4718
|
+
}
|
|
4719
|
+
const baseSemitone = ModelUtils._degreeSemitones[spelling.degree] + spelling.accidentalOffset;
|
|
4720
|
+
const octave = Math.floor((noteValue - baseSemitone) / 12) - 1;
|
|
4721
|
+
return {
|
|
4722
|
+
degree: spelling.degree,
|
|
4723
|
+
accidentalOffset: spelling.accidentalOffset,
|
|
4724
|
+
chroma,
|
|
4725
|
+
octave
|
|
4726
|
+
};
|
|
4727
|
+
}
|
|
4728
|
+
static computeAccidental(keySignature, accidentalMode, noteValue, quarterBend, currentAccidentalOffset = null) {
|
|
4729
|
+
const spelling = ModelUtils.resolveSpelling(keySignature, noteValue, accidentalMode);
|
|
4730
|
+
return ModelUtils.computeAccidentalForSpelling(keySignature, accidentalMode, spelling, quarterBend, currentAccidentalOffset);
|
|
4731
|
+
}
|
|
4732
|
+
static computeAccidentalForSpelling(keySignature, accidentalMode, spelling, quarterBend, currentAccidentalOffset = null) {
|
|
4733
|
+
if (accidentalMode === NoteAccidentalMode.ForceNone) {
|
|
4734
|
+
return AccidentalType.None;
|
|
4735
|
+
}
|
|
4736
|
+
if (quarterBend) {
|
|
4737
|
+
if (spelling.accidentalOffset > 0) {
|
|
4738
|
+
return AccidentalType.SharpQuarterNoteUp;
|
|
4739
|
+
}
|
|
4740
|
+
if (spelling.accidentalOffset < 0) {
|
|
4741
|
+
return AccidentalType.FlatQuarterNoteUp;
|
|
4742
|
+
}
|
|
4743
|
+
return AccidentalType.NaturalQuarterNoteUp;
|
|
4744
|
+
}
|
|
4745
|
+
const desiredOffset = spelling.accidentalOffset;
|
|
4746
|
+
const ksOffset = ModelUtils.getKeySignatureAccidentalOffset(keySignature, spelling.degree);
|
|
4747
|
+
// already active in bar -> no accidental needed
|
|
4748
|
+
if (currentAccidentalOffset === desiredOffset) {
|
|
4749
|
+
return AccidentalType.None;
|
|
4750
|
+
}
|
|
4751
|
+
// key signature already defines the accidental and no explicit accidental is active
|
|
4752
|
+
if (currentAccidentalOffset == null && desiredOffset === ksOffset) {
|
|
4753
|
+
return AccidentalType.None;
|
|
4754
|
+
}
|
|
4755
|
+
return ModelUtils.accidentalOffsetToType(desiredOffset);
|
|
4756
|
+
}
|
|
4757
|
+
static accidentalOffsetToType(offset) {
|
|
4758
|
+
return ModelUtils._accidentalOffsetToType.has(offset)
|
|
4759
|
+
? ModelUtils._accidentalOffsetToType.get(offset)
|
|
4760
|
+
: AccidentalType.None;
|
|
4761
|
+
}
|
|
4762
|
+
static _getPreferredSpellingForKeySignature(keySignature, chroma) {
|
|
4763
|
+
const candidates = ModelUtils._spellingCandidates[chroma];
|
|
4764
|
+
const ksMatch = candidates.find(c => ModelUtils.getKeySignatureAccidentalOffset(keySignature, c.degree) === c.accidentalOffset);
|
|
4765
|
+
if (ksMatch) {
|
|
4766
|
+
return ksMatch;
|
|
4767
|
+
}
|
|
4768
|
+
const preferFlat = ModelUtils.keySignatureIsFlat(keySignature);
|
|
4769
|
+
return preferFlat ? ModelUtils._flatPreferredSpellings[chroma] : ModelUtils._sharpPreferredSpellings[chroma];
|
|
4770
|
+
}
|
|
4771
|
+
static _majorKeySignatureTonicDegrees = [
|
|
4772
|
+
// Flats: Cb, Gb, Db, Ab, Eb, Bb, F
|
|
4773
|
+
0, 4, 1, 5, 2, 6, 3,
|
|
4774
|
+
// Natural: C
|
|
4775
|
+
0,
|
|
4776
|
+
// Sharps: G, D, A, E, B, F#, C#
|
|
4777
|
+
4, 1, 5, 2, 6, 3, 0
|
|
4778
|
+
];
|
|
4779
|
+
static _minorKeySignatureTonicDegrees = [
|
|
4780
|
+
// Flats: Ab, Eb, Bb, F, C, G, D
|
|
4781
|
+
5, 2, 6, 3, 0, 4, 1,
|
|
4782
|
+
// Natural: A
|
|
4783
|
+
5,
|
|
4784
|
+
// Sharps: E, B, F#, C#, G#, D#, A#
|
|
4785
|
+
2, 6, 3, 0, 4, 1, 5
|
|
4786
|
+
];
|
|
4787
|
+
static getKeySignatureTonicDegree(keySignature, keySignatureType) {
|
|
4788
|
+
const ksi = keySignature + 7;
|
|
4789
|
+
return keySignatureType === KeySignatureType.Minor
|
|
4790
|
+
? ModelUtils._minorKeySignatureTonicDegrees[ksi]
|
|
4791
|
+
: ModelUtils._majorKeySignatureTonicDegrees[ksi];
|
|
4792
|
+
}
|
|
4689
4793
|
}
|
|
4690
4794
|
|
|
4691
4795
|
/**
|
|
@@ -5396,7 +5500,8 @@ class PercussionMapper {
|
|
|
5396
5500
|
}
|
|
5397
5501
|
}
|
|
5398
5502
|
}
|
|
5399
|
-
|
|
5503
|
+
// unknown combination, should not happen, fallback to some default value (Snare hit)
|
|
5504
|
+
return 'Snare (hit)';
|
|
5400
5505
|
}
|
|
5401
5506
|
static getArticulation(n) {
|
|
5402
5507
|
const articulationIndex = n.percussionArticulation;
|
|
@@ -15572,7 +15677,11 @@ class AlphaTex1LanguageHandler {
|
|
|
15572
15677
|
const slurId = `s${note.slurOrigin.id}`;
|
|
15573
15678
|
Atnf.prop(properties, 'slur', Atnf.identValue(slurId));
|
|
15574
15679
|
}
|
|
15575
|
-
|
|
15680
|
+
// NOTE: it would be better to check via accidentalhelper what accidentals we really need to force
|
|
15681
|
+
const skipAccidental = note.accidentalMode === NoteAccidentalMode.Default ||
|
|
15682
|
+
(note.beat.voice.bar.keySignature === KeySignature.C &&
|
|
15683
|
+
note.accidentalMode === NoteAccidentalMode.ForceNatural);
|
|
15684
|
+
if (!skipAccidental) {
|
|
15576
15685
|
Atnf.prop(properties, 'acc', Atnf.identValue(ModelUtils.reverseAccidentalModeMapping.get(note.accidentalMode)));
|
|
15577
15686
|
}
|
|
15578
15687
|
switch (note.ornament) {
|
|
@@ -19537,6 +19646,24 @@ var Direction;
|
|
|
19537
19646
|
*/
|
|
19538
19647
|
class Gp3To5Importer extends ScoreImporter {
|
|
19539
19648
|
static _versionString = 'FICHIER GUITAR PRO ';
|
|
19649
|
+
// NOTE: General Midi only defines percussion instruments from 35-81
|
|
19650
|
+
// Guitar Pro 5 allowed GS extensions (27-34 and 82-87)
|
|
19651
|
+
// GP7-8 do not have all these definitions anymore, this lookup ensures some fallback
|
|
19652
|
+
// (even if they are not correct)
|
|
19653
|
+
// we can support this properly in future when we allow custom alphaTex articulation definitions
|
|
19654
|
+
// then we don't need to rely on GP specifics anymore but handle things on export/import
|
|
19655
|
+
static _gp5PercussionInstrumentMap = new Map([
|
|
19656
|
+
// High Q -> GS "High Q / Filter Snap"
|
|
19657
|
+
[27, 42],
|
|
19658
|
+
// Slap
|
|
19659
|
+
[28, 60],
|
|
19660
|
+
// Scratch Push
|
|
19661
|
+
[29, 29],
|
|
19662
|
+
// Scratch Pull
|
|
19663
|
+
[30, 30],
|
|
19664
|
+
// Square Click
|
|
19665
|
+
[32, 31]
|
|
19666
|
+
]);
|
|
19540
19667
|
_versionNumber = 0;
|
|
19541
19668
|
_score;
|
|
19542
19669
|
_globalTripletFeel = TripletFeel.NoTripletFeel;
|
|
@@ -19883,9 +20010,9 @@ class Gp3To5Importer extends ScoreImporter {
|
|
|
19883
20010
|
}
|
|
19884
20011
|
}
|
|
19885
20012
|
/**
|
|
19886
|
-
* Guitar Pro 3-6 changes to a bass clef if any string tuning is below
|
|
20013
|
+
* Guitar Pro 3-6 changes to a bass clef if any string tuning is below B1
|
|
19887
20014
|
*/
|
|
19888
|
-
static _bassClefTuningThreshold = ModelUtils.parseTuning('
|
|
20015
|
+
static _bassClefTuningThreshold = ModelUtils.parseTuning('B1').realValue;
|
|
19889
20016
|
readTrack() {
|
|
19890
20017
|
const newTrack = new Track();
|
|
19891
20018
|
newTrack.ensureStaveCount(1);
|
|
@@ -20606,7 +20733,9 @@ class Gp3To5Importer extends ScoreImporter {
|
|
|
20606
20733
|
this.readNoteEffects(track, voice, beat, newNote);
|
|
20607
20734
|
}
|
|
20608
20735
|
if (bar.staff.isPercussion) {
|
|
20609
|
-
newNote.percussionArticulation = newNote.fret
|
|
20736
|
+
newNote.percussionArticulation = Gp3To5Importer._gp5PercussionInstrumentMap.has(newNote.fret)
|
|
20737
|
+
? Gp3To5Importer._gp5PercussionInstrumentMap.get(newNote.fret)
|
|
20738
|
+
: newNote.fret;
|
|
20610
20739
|
newNote.string = -1;
|
|
20611
20740
|
newNote.fret = -1;
|
|
20612
20741
|
}
|
|
@@ -23858,6 +23987,9 @@ class GpifParser {
|
|
|
23858
23987
|
switch (c.localName) {
|
|
23859
23988
|
case 'Accidental':
|
|
23860
23989
|
switch (c.innerText) {
|
|
23990
|
+
case '':
|
|
23991
|
+
note.accidentalMode = NoteAccidentalMode.ForceNatural;
|
|
23992
|
+
break;
|
|
23861
23993
|
case 'x':
|
|
23862
23994
|
note.accidentalMode = NoteAccidentalMode.ForceDoubleSharp;
|
|
23863
23995
|
break;
|
|
@@ -24896,13 +25028,9 @@ class AccidentalHelper {
|
|
|
24896
25028
|
*/
|
|
24897
25029
|
static _octaveSteps = [38, 32, 30, 26, 38];
|
|
24898
25030
|
/**
|
|
24899
|
-
*
|
|
24900
|
-
*/
|
|
24901
|
-
static sharpNoteSteps = [0, 0, 1, 1, 2, 3, 3, 4, 4, 5, 5, 6];
|
|
24902
|
-
/**
|
|
24903
|
-
* The step offsets of the notes within an octave in case of for flat keysignatures
|
|
25031
|
+
* Diatonic step offsets within an octave.
|
|
24904
25032
|
*/
|
|
24905
|
-
static
|
|
25033
|
+
static _diatonicSteps = [0, 1, 2, 3, 4, 5, 6];
|
|
24906
25034
|
_registeredAccidentals = new Map();
|
|
24907
25035
|
_appliedScoreSteps = new Map();
|
|
24908
25036
|
_appliedScoreStepsByValue = new Map();
|
|
@@ -24934,23 +25062,7 @@ class AccidentalHelper {
|
|
|
24934
25062
|
return PercussionMapper.getArticulation(note)?.staffLine ?? 0;
|
|
24935
25063
|
}
|
|
24936
25064
|
static getNoteValue(note) {
|
|
24937
|
-
|
|
24938
|
-
// adjust note height according to accidentals enforced
|
|
24939
|
-
switch (note.accidentalMode) {
|
|
24940
|
-
case NoteAccidentalMode.ForceDoubleFlat:
|
|
24941
|
-
noteValue += 2;
|
|
24942
|
-
break;
|
|
24943
|
-
case NoteAccidentalMode.ForceDoubleSharp:
|
|
24944
|
-
noteValue -= 2;
|
|
24945
|
-
break;
|
|
24946
|
-
case NoteAccidentalMode.ForceFlat:
|
|
24947
|
-
noteValue += 1;
|
|
24948
|
-
break;
|
|
24949
|
-
case NoteAccidentalMode.ForceSharp:
|
|
24950
|
-
noteValue -= 1;
|
|
24951
|
-
break;
|
|
24952
|
-
}
|
|
24953
|
-
return noteValue;
|
|
25065
|
+
return note.displayValue;
|
|
24954
25066
|
}
|
|
24955
25067
|
/**
|
|
24956
25068
|
* Calculates the accidental for the given note and assignes the value to it.
|
|
@@ -24982,7 +25094,8 @@ class AccidentalHelper {
|
|
|
24982
25094
|
steps = AccidentalHelper.getPercussionSteps(note);
|
|
24983
25095
|
}
|
|
24984
25096
|
else {
|
|
24985
|
-
|
|
25097
|
+
const spelling = ModelUtils.resolveSpelling(bar.keySignature, noteValue, note.accidentalMode);
|
|
25098
|
+
steps = AccidentalHelper.calculateNoteSteps(bar.clef, spelling);
|
|
24986
25099
|
}
|
|
24987
25100
|
return steps;
|
|
24988
25101
|
}
|
|
@@ -24995,11 +25108,12 @@ class AccidentalHelper {
|
|
|
24995
25108
|
}
|
|
24996
25109
|
else {
|
|
24997
25110
|
const accidentalMode = note ? note.accidentalMode : NoteAccidentalMode.Default;
|
|
24998
|
-
|
|
24999
|
-
|
|
25111
|
+
const spelling = ModelUtils.resolveSpelling(this._bar.keySignature, noteValue, accidentalMode);
|
|
25112
|
+
steps = AccidentalHelper.calculateNoteSteps(this._bar.clef, spelling);
|
|
25113
|
+
const currentAccidentalOffset = this._registeredAccidentals.has(steps)
|
|
25000
25114
|
? this._registeredAccidentals.get(steps)
|
|
25001
25115
|
: null;
|
|
25002
|
-
accidentalToSet = ModelUtils.
|
|
25116
|
+
accidentalToSet = ModelUtils.computeAccidentalForSpelling(this._bar.keySignature, accidentalMode, spelling, quarterBend, currentAccidentalOffset);
|
|
25003
25117
|
let skipAccidental = false;
|
|
25004
25118
|
switch (accidentalToSet) {
|
|
25005
25119
|
case AccidentalType.NaturalQuarterNoteUp:
|
|
@@ -25024,14 +25138,12 @@ class AccidentalHelper {
|
|
|
25024
25138
|
if (skipAccidental) {
|
|
25025
25139
|
accidentalToSet = AccidentalType.None;
|
|
25026
25140
|
}
|
|
25027
|
-
else {
|
|
25028
|
-
// do we need an accidental on the note?
|
|
25029
|
-
if (accidentalToSet !== AccidentalType.None) {
|
|
25030
|
-
this._registeredAccidentals.set(steps, accidentalToSet);
|
|
25031
|
-
}
|
|
25032
|
-
}
|
|
25033
25141
|
break;
|
|
25034
25142
|
}
|
|
25143
|
+
const shouldRegister = !quarterBend && accidentalToSet !== AccidentalType.None;
|
|
25144
|
+
if (shouldRegister) {
|
|
25145
|
+
this._registeredAccidentals.set(steps, spelling.accidentalOffset);
|
|
25146
|
+
}
|
|
25035
25147
|
}
|
|
25036
25148
|
if (note) {
|
|
25037
25149
|
this._appliedScoreSteps.set(note.id, steps);
|
|
@@ -25083,21 +25195,14 @@ class AccidentalHelper {
|
|
|
25083
25195
|
getMinStepsNote(b) {
|
|
25084
25196
|
return this._beatSteps.has(b.id) ? this._beatSteps.get(b.id).minStepsNote : null;
|
|
25085
25197
|
}
|
|
25086
|
-
static calculateNoteSteps(
|
|
25087
|
-
const value = noteValue;
|
|
25088
|
-
const ks = keySignature;
|
|
25198
|
+
static calculateNoteSteps(clef, spelling) {
|
|
25089
25199
|
const clefValue = clef;
|
|
25090
|
-
const index = value % 12;
|
|
25091
|
-
const octave = ((value / 12) | 0) - 1;
|
|
25092
25200
|
// Initial Position
|
|
25093
25201
|
let steps = AccidentalHelper._octaveSteps[clefValue];
|
|
25094
25202
|
// Move to Octave
|
|
25095
|
-
steps -= octave * AccidentalHelper._stepsPerOctave;
|
|
25096
|
-
//
|
|
25097
|
-
|
|
25098
|
-
? AccidentalHelper.sharpNoteSteps
|
|
25099
|
-
: AccidentalHelper.flatNoteSteps;
|
|
25100
|
-
steps -= stepList[index];
|
|
25203
|
+
steps -= spelling.octave * AccidentalHelper._stepsPerOctave;
|
|
25204
|
+
// Move within octave
|
|
25205
|
+
steps -= AccidentalHelper._diatonicSteps[spelling.degree];
|
|
25101
25206
|
return steps;
|
|
25102
25207
|
}
|
|
25103
25208
|
getNoteSteps(n) {
|
|
@@ -25202,7 +25307,8 @@ class TrackInfo {
|
|
|
25202
25307
|
musicXmlStaffSteps = 4; // middle of bar
|
|
25203
25308
|
}
|
|
25204
25309
|
else {
|
|
25205
|
-
|
|
25310
|
+
const spelling = ModelUtils.resolveSpelling(bar.keySignature, noteValue, NoteAccidentalMode.Default);
|
|
25311
|
+
musicXmlStaffSteps = AccidentalHelper.calculateNoteSteps(bar.clef, spelling);
|
|
25206
25312
|
}
|
|
25207
25313
|
// to translate this into the "staffLine" semantics we need to subtract additionally the steps "missing" from the absent lines
|
|
25208
25314
|
const actualSteps = note.beat.voice.bar.staff.standardNotationLineCount * 2 - 1;
|
|
@@ -47056,9 +47162,14 @@ var MidiTickLookupFindBeatResultCursorMode;
|
|
|
47056
47162
|
*/
|
|
47057
47163
|
MidiTickLookupFindBeatResultCursorMode[MidiTickLookupFindBeatResultCursorMode["ToNextBext"] = 1] = "ToNextBext";
|
|
47058
47164
|
/**
|
|
47059
|
-
*
|
|
47165
|
+
* @deprecated replaced by {@link ToEndOfBeat}
|
|
47060
47166
|
*/
|
|
47061
47167
|
MidiTickLookupFindBeatResultCursorMode[MidiTickLookupFindBeatResultCursorMode["ToEndOfBar"] = 2] = "ToEndOfBar";
|
|
47168
|
+
/**
|
|
47169
|
+
* The cursor should animate to the end of the **beat** (typically on repeats and jumps)
|
|
47170
|
+
* (this is named end of bar historically)
|
|
47171
|
+
*/
|
|
47172
|
+
MidiTickLookupFindBeatResultCursorMode[MidiTickLookupFindBeatResultCursorMode["ToEndOfBeat"] = 3] = "ToEndOfBeat";
|
|
47062
47173
|
})(MidiTickLookupFindBeatResultCursorMode || (MidiTickLookupFindBeatResultCursorMode = {}));
|
|
47063
47174
|
/**
|
|
47064
47175
|
* Represents the results of searching the currently played beat.
|
|
@@ -47206,6 +47317,11 @@ class MidiTickLookup {
|
|
|
47206
47317
|
* This info allows building the correct "next" beat and duration.
|
|
47207
47318
|
*/
|
|
47208
47319
|
multiBarRestInfo = null;
|
|
47320
|
+
/**
|
|
47321
|
+
* An optional playback range to consider when performing lookups.
|
|
47322
|
+
* This will mainly influence the used {@link MidiTickLookupFindBeatResultCursorMode}
|
|
47323
|
+
*/
|
|
47324
|
+
playbackRange = null;
|
|
47209
47325
|
/**
|
|
47210
47326
|
* Finds the currently played beat given a list of tracks and the current time.
|
|
47211
47327
|
* @param trackLookup The tracks indices in which to search the played beat for.
|
|
@@ -47231,6 +47347,13 @@ class MidiTickLookup {
|
|
|
47231
47347
|
if (!result) {
|
|
47232
47348
|
result = this._findBeatSlow(checker, currentBeatHint, tick, false);
|
|
47233
47349
|
}
|
|
47350
|
+
if (result) {
|
|
47351
|
+
const playbackRange = this.playbackRange;
|
|
47352
|
+
const isBeyondRangeEnd = playbackRange !== null && result.start >= playbackRange.endTick;
|
|
47353
|
+
if (isBeyondRangeEnd) {
|
|
47354
|
+
return null;
|
|
47355
|
+
}
|
|
47356
|
+
}
|
|
47234
47357
|
return result;
|
|
47235
47358
|
}
|
|
47236
47359
|
_findBeatFast(checker, currentBeatHint, tick) {
|
|
@@ -47270,20 +47393,24 @@ class MidiTickLookup {
|
|
|
47270
47393
|
if (current.nextBeat) {
|
|
47271
47394
|
current.tickDuration = current.nextBeat.start - current.start;
|
|
47272
47395
|
current.cursorMode = MidiTickLookupFindBeatResultCursorMode.ToNextBext;
|
|
47396
|
+
// jump back
|
|
47273
47397
|
if (current.nextBeat.masterBar.masterBar.index !== endMasterBar.masterBar.index + 1 &&
|
|
47274
47398
|
(current.nextBeat.masterBar.masterBar.index !== endMasterBar.masterBar.index ||
|
|
47275
47399
|
current.nextBeat.beat.playbackStart <= current.beat.playbackStart)) {
|
|
47276
|
-
current.cursorMode = MidiTickLookupFindBeatResultCursorMode.
|
|
47400
|
+
current.cursorMode = MidiTickLookupFindBeatResultCursorMode.ToEndOfBeat;
|
|
47401
|
+
}
|
|
47402
|
+
else if (this.playbackRange !== null && this.playbackRange.endTick <= current.nextBeat.start) {
|
|
47403
|
+
current.cursorMode = MidiTickLookupFindBeatResultCursorMode.ToEndOfBeat;
|
|
47277
47404
|
}
|
|
47278
47405
|
}
|
|
47279
47406
|
else {
|
|
47280
47407
|
current.tickDuration = endMasterBar.nextMasterBar.end - current.start;
|
|
47281
|
-
current.cursorMode = MidiTickLookupFindBeatResultCursorMode.
|
|
47408
|
+
current.cursorMode = MidiTickLookupFindBeatResultCursorMode.ToEndOfBeat;
|
|
47282
47409
|
}
|
|
47283
47410
|
}
|
|
47284
47411
|
else {
|
|
47285
47412
|
current.tickDuration = endMasterBar.end - current.start;
|
|
47286
|
-
current.cursorMode = MidiTickLookupFindBeatResultCursorMode.
|
|
47413
|
+
current.cursorMode = MidiTickLookupFindBeatResultCursorMode.ToEndOfBeat;
|
|
47287
47414
|
}
|
|
47288
47415
|
}
|
|
47289
47416
|
else {
|
|
@@ -47291,7 +47418,7 @@ class MidiTickLookup {
|
|
|
47291
47418
|
// this is wierd, we have a masterbar without known tick?
|
|
47292
47419
|
// make a best guess with the number of bars
|
|
47293
47420
|
current.tickDuration = (current.masterBar.end - current.masterBar.start) * (group.length + 1);
|
|
47294
|
-
current.cursorMode = MidiTickLookupFindBeatResultCursorMode.
|
|
47421
|
+
current.cursorMode = MidiTickLookupFindBeatResultCursorMode.ToEndOfBeat;
|
|
47295
47422
|
}
|
|
47296
47423
|
current.calculateDuration();
|
|
47297
47424
|
}
|
|
@@ -47317,16 +47444,20 @@ class MidiTickLookup {
|
|
|
47317
47444
|
}
|
|
47318
47445
|
else {
|
|
47319
47446
|
current.tickDuration = current.masterBar.end - current.start;
|
|
47320
|
-
current.cursorMode = MidiTickLookupFindBeatResultCursorMode.
|
|
47447
|
+
current.cursorMode = MidiTickLookupFindBeatResultCursorMode.ToEndOfBeat;
|
|
47321
47448
|
current.calculateDuration();
|
|
47322
47449
|
}
|
|
47323
|
-
|
|
47324
|
-
|
|
47325
|
-
|
|
47326
|
-
current.nextBeat.masterBar.masterBar.index !== current.masterBar.masterBar.index + 1 &&
|
|
47327
|
-
|
|
47328
|
-
|
|
47329
|
-
|
|
47450
|
+
if (current.nextBeat) {
|
|
47451
|
+
// if the next beat is not directly the next master bar (e.g. jumping back or forth)
|
|
47452
|
+
// we report no next beat and animate to the end
|
|
47453
|
+
if (current.nextBeat.masterBar.masterBar.index !== current.masterBar.masterBar.index + 1 &&
|
|
47454
|
+
(current.nextBeat.masterBar.masterBar.index !== current.masterBar.masterBar.index ||
|
|
47455
|
+
current.nextBeat.beat.playbackStart <= current.beat.playbackStart)) {
|
|
47456
|
+
current.cursorMode = MidiTickLookupFindBeatResultCursorMode.ToEndOfBeat;
|
|
47457
|
+
}
|
|
47458
|
+
else if (this.playbackRange !== null && this.playbackRange.endTick <= current.nextBeat.start) {
|
|
47459
|
+
current.cursorMode = MidiTickLookupFindBeatResultCursorMode.ToEndOfBeat;
|
|
47460
|
+
}
|
|
47330
47461
|
}
|
|
47331
47462
|
}
|
|
47332
47463
|
_isMultiBarRestResult(current) {
|
|
@@ -49352,22 +49483,61 @@ class MidiFileGenerator {
|
|
|
49352
49483
|
}
|
|
49353
49484
|
|
|
49354
49485
|
/**
|
|
49355
|
-
*
|
|
49356
|
-
*
|
|
49486
|
+
* A cursor handler which animates the beat cursor to the next beat or end of the beat bounds
|
|
49487
|
+
* depending on the cursor mode.
|
|
49488
|
+
* @internal
|
|
49357
49489
|
*/
|
|
49358
|
-
class
|
|
49359
|
-
|
|
49360
|
-
|
|
49361
|
-
|
|
49362
|
-
|
|
49363
|
-
|
|
49364
|
-
|
|
49365
|
-
|
|
49366
|
-
|
|
49367
|
-
|
|
49368
|
-
|
|
49369
|
-
|
|
49370
|
-
|
|
49490
|
+
class ToNextBeatAnimatingCursorHandler {
|
|
49491
|
+
onAttach(_cursors) {
|
|
49492
|
+
}
|
|
49493
|
+
onDetach(_cursors) {
|
|
49494
|
+
}
|
|
49495
|
+
placeBeatCursor(beatCursor, beatBounds, startBeatX) {
|
|
49496
|
+
const barBoundings = beatBounds.barBounds.masterBarBounds;
|
|
49497
|
+
const barBounds = barBoundings.visualBounds;
|
|
49498
|
+
beatCursor.transitionToX(0, startBeatX);
|
|
49499
|
+
beatCursor.setBounds(startBeatX, barBounds.y, 1, barBounds.h);
|
|
49500
|
+
}
|
|
49501
|
+
placeBarCursor(barCursor, beatBounds) {
|
|
49502
|
+
const barBoundings = beatBounds.barBounds.masterBarBounds;
|
|
49503
|
+
const barBounds = barBoundings.visualBounds;
|
|
49504
|
+
barCursor.setBounds(barBounds.x, barBounds.y, barBounds.w, barBounds.h);
|
|
49505
|
+
}
|
|
49506
|
+
transitionBeatCursor(beatCursor, _beatBounds, startBeatX, nextBeatX, duration, cursorMode) {
|
|
49507
|
+
// it can happen that the cursor reaches the target position slightly too early (especially on backing tracks)
|
|
49508
|
+
// to avoid the cursor stopping, causing a wierd look, we animate the cursor to the double position in double time.
|
|
49509
|
+
// beatCursor!.transitionToX((duration / cursorSpeed), nextBeatX);
|
|
49510
|
+
const factor = cursorMode === MidiTickLookupFindBeatResultCursorMode.ToNextBext ? 2 : 1;
|
|
49511
|
+
nextBeatX = startBeatX + (nextBeatX - startBeatX) * factor;
|
|
49512
|
+
duration = duration * factor;
|
|
49513
|
+
// we need to put the transition to an own animation frame
|
|
49514
|
+
// otherwise the stop animation above is not applied.
|
|
49515
|
+
beatCursor.transitionToX(duration, nextBeatX);
|
|
49516
|
+
}
|
|
49517
|
+
}
|
|
49518
|
+
/**
|
|
49519
|
+
* A cursor handler which just places the bar and beat cursor without any animations applied.
|
|
49520
|
+
* @internal
|
|
49521
|
+
*/
|
|
49522
|
+
class NonAnimatingCursorHandler {
|
|
49523
|
+
onAttach(_cursors) {
|
|
49524
|
+
}
|
|
49525
|
+
onDetach(_cursors) {
|
|
49526
|
+
}
|
|
49527
|
+
placeBeatCursor(beatCursor, beatBounds, startBeatX) {
|
|
49528
|
+
const barBoundings = beatBounds.barBounds.masterBarBounds;
|
|
49529
|
+
const barBounds = barBoundings.visualBounds;
|
|
49530
|
+
beatCursor.transitionToX(0, startBeatX);
|
|
49531
|
+
beatCursor.setBounds(startBeatX, barBounds.y, 1, barBounds.h);
|
|
49532
|
+
}
|
|
49533
|
+
placeBarCursor(barCursor, beatBounds) {
|
|
49534
|
+
const barBoundings = beatBounds.barBounds.masterBarBounds;
|
|
49535
|
+
const barBounds = barBoundings.visualBounds;
|
|
49536
|
+
barCursor.setBounds(barBounds.x, barBounds.y, barBounds.w, barBounds.h);
|
|
49537
|
+
}
|
|
49538
|
+
transitionBeatCursor(beatCursor, beatBounds, startBeatX, _nextBeatX, _duration, _cursorMode) {
|
|
49539
|
+
this.placeBeatCursor(beatCursor, beatBounds, startBeatX);
|
|
49540
|
+
}
|
|
49371
49541
|
}
|
|
49372
49542
|
|
|
49373
49543
|
/**
|
|
@@ -49809,6 +49979,25 @@ class ScoreRendererWrapper {
|
|
|
49809
49979
|
error = new EventEmitterOfT();
|
|
49810
49980
|
}
|
|
49811
49981
|
|
|
49982
|
+
/**
|
|
49983
|
+
* Represents the information related to a resize event.
|
|
49984
|
+
* @public
|
|
49985
|
+
*/
|
|
49986
|
+
class ResizeEventArgs {
|
|
49987
|
+
/**
|
|
49988
|
+
* Gets the size before the resizing happened.
|
|
49989
|
+
*/
|
|
49990
|
+
oldWidth = 0;
|
|
49991
|
+
/**
|
|
49992
|
+
* Gets the size after the resize was complete.
|
|
49993
|
+
*/
|
|
49994
|
+
newWidth = 0;
|
|
49995
|
+
/**
|
|
49996
|
+
* Gets the settings currently used for rendering.
|
|
49997
|
+
*/
|
|
49998
|
+
settings = null;
|
|
49999
|
+
}
|
|
50000
|
+
|
|
49812
50001
|
/**
|
|
49813
50002
|
* Some basic scroll handler checking for changed offsets and scroll if changed.
|
|
49814
50003
|
* @internal
|
|
@@ -50678,6 +50867,42 @@ class ExternalMediaPlayer extends BackingTrackPlayer {
|
|
|
50678
50867
|
}
|
|
50679
50868
|
}
|
|
50680
50869
|
|
|
50870
|
+
/**
|
|
50871
|
+
* This wrapper holds all cursor related elements.
|
|
50872
|
+
* @public
|
|
50873
|
+
*/
|
|
50874
|
+
class Cursors {
|
|
50875
|
+
/**
|
|
50876
|
+
* Gets the element that spans across the whole music sheet and holds the other cursor elements.
|
|
50877
|
+
*/
|
|
50878
|
+
cursorWrapper;
|
|
50879
|
+
/**
|
|
50880
|
+
* Gets the element that is positioned above the bar that is currently played.
|
|
50881
|
+
*/
|
|
50882
|
+
barCursor;
|
|
50883
|
+
/**
|
|
50884
|
+
* Gets the element that is positioned above the beat that is currently played.
|
|
50885
|
+
*/
|
|
50886
|
+
beatCursor;
|
|
50887
|
+
/**
|
|
50888
|
+
* Gets the element that spans across the whole music sheet and will hold any selection related elements.
|
|
50889
|
+
*/
|
|
50890
|
+
selectionWrapper;
|
|
50891
|
+
/**
|
|
50892
|
+
* Initializes a new instance of the {@link Cursors} class.
|
|
50893
|
+
* @param cursorWrapper
|
|
50894
|
+
* @param barCursor
|
|
50895
|
+
* @param beatCursor
|
|
50896
|
+
* @param selectionWrapper
|
|
50897
|
+
*/
|
|
50898
|
+
constructor(cursorWrapper, barCursor, beatCursor, selectionWrapper) {
|
|
50899
|
+
this.cursorWrapper = cursorWrapper;
|
|
50900
|
+
this.barCursor = barCursor;
|
|
50901
|
+
this.beatCursor = beatCursor;
|
|
50902
|
+
this.selectionWrapper = selectionWrapper;
|
|
50903
|
+
}
|
|
50904
|
+
}
|
|
50905
|
+
|
|
50681
50906
|
/**
|
|
50682
50907
|
* @internal
|
|
50683
50908
|
*/
|
|
@@ -50709,6 +50934,8 @@ class AlphaTabApiBase {
|
|
|
50709
50934
|
_player;
|
|
50710
50935
|
_renderer;
|
|
50711
50936
|
_defaultScrollHandler;
|
|
50937
|
+
_defaultCursorHandler;
|
|
50938
|
+
_customCursorHandler;
|
|
50712
50939
|
/**
|
|
50713
50940
|
* An indicator by how many midi-ticks the song contents are shifted.
|
|
50714
50941
|
* Grace beats at start might require a shift for the first beat to start at 0.
|
|
@@ -51480,6 +51707,80 @@ class AlphaTabApiBase {
|
|
|
51480
51707
|
this.uiFacade.canRenderChanged.on(() => this.render(renderHints));
|
|
51481
51708
|
}
|
|
51482
51709
|
}
|
|
51710
|
+
/**
|
|
51711
|
+
* A custom cursor handler which will be used to update the cursor positions during playback.
|
|
51712
|
+
*
|
|
51713
|
+
* @category Properties - Player
|
|
51714
|
+
* @since 1.8.1
|
|
51715
|
+
* @example
|
|
51716
|
+
* JavaScript
|
|
51717
|
+
* ```js
|
|
51718
|
+
* const api = new alphaTab.AlphaTabApi(document.querySelector('#alphaTab'));
|
|
51719
|
+
* api.customCursorHandler = {
|
|
51720
|
+
* _customAdorner: undefined,
|
|
51721
|
+
* onAttach(cursors) {
|
|
51722
|
+
* this._customAdorner = document.createElement('div');
|
|
51723
|
+
* this._customAdorner.classList.add('cursor-adorner');
|
|
51724
|
+
* cursors.cursorWrapper.element.appendChild(this._customAdorner);
|
|
51725
|
+
* },
|
|
51726
|
+
* onDetach(cursors) { this._customAdorner.remove(); },
|
|
51727
|
+
* placeBarCursor(barCursor, beatBounds) {
|
|
51728
|
+
* const barBoundings = beatBounds.barBounds.masterBarBounds;
|
|
51729
|
+
* const barBounds = barBoundings.visualBounds;
|
|
51730
|
+
* barCursor.setBounds(barBounds.x, barBounds.y, barBounds.w, barBounds.h);
|
|
51731
|
+
* },
|
|
51732
|
+
* placeBeatCursor(beatCursor, beatBounds, startBeatX) {
|
|
51733
|
+
* const barBoundings = beatBounds.barBounds.masterBarBounds;
|
|
51734
|
+
* const barBounds = barBoundings.visualBounds;
|
|
51735
|
+
* beatCursor.transitionToX(0, startBeatX);
|
|
51736
|
+
* beatCursor.setBounds(startBeatX, barBounds.y, 1, barBounds.h);
|
|
51737
|
+
* this._customAdorner.style.left = startBeatX + 'px';
|
|
51738
|
+
* this._customAdorner.style.top = (barBounds.y - 10) + 'px';
|
|
51739
|
+
* this._customAdorner.style.width = '1px';
|
|
51740
|
+
* this._customAdorner.style.height = '10px';
|
|
51741
|
+
* this._customAdorner.style.transition = 'left 0ms linear'; // stop animation
|
|
51742
|
+
* },
|
|
51743
|
+
* transitionBeatCursor(beatCursor, beatBounds, startBeatX, endBeatX, duration, cursorMode) {
|
|
51744
|
+
* this._customAdorner.style.transition = `left ${duration}ms linear`; // start animation
|
|
51745
|
+
* this._customAdorner.style.left = endBeatX + 'px';
|
|
51746
|
+
* }
|
|
51747
|
+
* }
|
|
51748
|
+
* ```
|
|
51749
|
+
*
|
|
51750
|
+
* @example
|
|
51751
|
+
* C#
|
|
51752
|
+
* ```cs
|
|
51753
|
+
* var api = new AlphaTabApi<MyControl>(...);
|
|
51754
|
+
* api.CustomCursorHandler = new CustomCursorHandler();
|
|
51755
|
+
* ```
|
|
51756
|
+
*
|
|
51757
|
+
* @example
|
|
51758
|
+
* Android
|
|
51759
|
+
* ```kotlin
|
|
51760
|
+
* val api = AlphaTabApi<MyControl>(...)
|
|
51761
|
+
* api.customCursorHandler = CustomCursorHandler();
|
|
51762
|
+
* ```
|
|
51763
|
+
*/
|
|
51764
|
+
get customCursorHandler() {
|
|
51765
|
+
return this._customCursorHandler;
|
|
51766
|
+
}
|
|
51767
|
+
set customCursorHandler(value) {
|
|
51768
|
+
if (this._customCursorHandler === value) {
|
|
51769
|
+
return;
|
|
51770
|
+
}
|
|
51771
|
+
const currentHandler = this._customCursorHandler ?? this._defaultCursorHandler;
|
|
51772
|
+
this._customCursorHandler = value;
|
|
51773
|
+
if (this._cursorWrapper) {
|
|
51774
|
+
const cursors = new Cursors(this._cursorWrapper, this._barCursor, this._beatCursor, this._selectionWrapper);
|
|
51775
|
+
currentHandler?.onDetach(cursors);
|
|
51776
|
+
if (value) {
|
|
51777
|
+
value?.onDetach(cursors);
|
|
51778
|
+
}
|
|
51779
|
+
else if (this._defaultCursorHandler) {
|
|
51780
|
+
this._defaultCursorHandler.onAttach(cursors);
|
|
51781
|
+
}
|
|
51782
|
+
}
|
|
51783
|
+
}
|
|
51483
51784
|
_tickCache = null;
|
|
51484
51785
|
/**
|
|
51485
51786
|
* A custom scroll handler which will be used to handle scrolling operations during playback.
|
|
@@ -51957,6 +52258,9 @@ class AlphaTabApiBase {
|
|
|
51957
52258
|
}
|
|
51958
52259
|
set playbackRange(value) {
|
|
51959
52260
|
this._player.playbackRange = value;
|
|
52261
|
+
if (this._tickCache) {
|
|
52262
|
+
this._tickCache.playbackRange = value;
|
|
52263
|
+
}
|
|
51960
52264
|
this._updateSelectionCursor(value);
|
|
51961
52265
|
}
|
|
51962
52266
|
/**
|
|
@@ -52104,6 +52408,7 @@ class AlphaTabApiBase {
|
|
|
52104
52408
|
generator.applyTranspositionPitches = false;
|
|
52105
52409
|
generator.generate();
|
|
52106
52410
|
this._tickCache = generator.tickLookup;
|
|
52411
|
+
this._tickCache.playbackRange = this.playbackRange;
|
|
52107
52412
|
this._onMidiLoad(midiFile);
|
|
52108
52413
|
const player = this._player;
|
|
52109
52414
|
player.midiTickShift = handler.tickShift;
|
|
@@ -52499,6 +52804,8 @@ class AlphaTabApiBase {
|
|
|
52499
52804
|
if (!this._cursorWrapper) {
|
|
52500
52805
|
return;
|
|
52501
52806
|
}
|
|
52807
|
+
const cursorHandler = this.customCursorHandler ?? this._defaultCursorHandler;
|
|
52808
|
+
cursorHandler?.onDetach(new Cursors(this._cursorWrapper, this._barCursor, this._beatCursor, this._selectionWrapper));
|
|
52502
52809
|
this.uiFacade.destroyCursors();
|
|
52503
52810
|
this._cursorWrapper = null;
|
|
52504
52811
|
this._barCursor = null;
|
|
@@ -52516,6 +52823,8 @@ class AlphaTabApiBase {
|
|
|
52516
52823
|
this._barCursor = cursors.barCursor;
|
|
52517
52824
|
this._beatCursor = cursors.beatCursor;
|
|
52518
52825
|
this._selectionWrapper = cursors.selectionWrapper;
|
|
52826
|
+
const cursorHandler = this.customCursorHandler ?? this._defaultCursorHandler;
|
|
52827
|
+
cursorHandler?.onAttach(cursors);
|
|
52519
52828
|
this._isInitialBeatCursorUpdate = true;
|
|
52520
52829
|
}
|
|
52521
52830
|
if (this._currentBeat !== null) {
|
|
@@ -52523,6 +52832,7 @@ class AlphaTabApiBase {
|
|
|
52523
52832
|
}
|
|
52524
52833
|
}
|
|
52525
52834
|
_updateCursors() {
|
|
52835
|
+
this._updateCursorHandler();
|
|
52526
52836
|
this._updateScrollHandler();
|
|
52527
52837
|
const enable = this._hasCursor;
|
|
52528
52838
|
if (enable) {
|
|
@@ -52532,6 +52842,21 @@ class AlphaTabApiBase {
|
|
|
52532
52842
|
this._destroyCursors();
|
|
52533
52843
|
}
|
|
52534
52844
|
}
|
|
52845
|
+
_cursorHandlerMode = false;
|
|
52846
|
+
_updateCursorHandler() {
|
|
52847
|
+
const currentHandler = this._defaultCursorHandler;
|
|
52848
|
+
const cursorHandlerMode = this.settings.player.enableAnimatedBeatCursor;
|
|
52849
|
+
// no change
|
|
52850
|
+
if (currentHandler !== undefined && this._cursorHandlerMode === cursorHandlerMode) {
|
|
52851
|
+
return;
|
|
52852
|
+
}
|
|
52853
|
+
if (cursorHandlerMode) {
|
|
52854
|
+
this._defaultCursorHandler = new ToNextBeatAnimatingCursorHandler();
|
|
52855
|
+
}
|
|
52856
|
+
else {
|
|
52857
|
+
this._defaultCursorHandler = new NonAnimatingCursorHandler();
|
|
52858
|
+
}
|
|
52859
|
+
}
|
|
52535
52860
|
_scrollHandlerMode = ScrollMode.Off;
|
|
52536
52861
|
_scrollHandlerVertical = true;
|
|
52537
52862
|
_updateScrollHandler() {
|
|
@@ -52599,9 +52924,6 @@ class AlphaTabApiBase {
|
|
|
52599
52924
|
*/
|
|
52600
52925
|
_cursorUpdateBeat(lookupResult, stop, shouldScroll, cursorSpeed, forceUpdate = false) {
|
|
52601
52926
|
const beat = lookupResult.beat;
|
|
52602
|
-
const nextBeat = lookupResult.nextBeat?.beat ?? null;
|
|
52603
|
-
const duration = lookupResult.duration;
|
|
52604
|
-
const beatsToHighlight = lookupResult.beatLookup.highlightedBeats;
|
|
52605
52927
|
if (!beat) {
|
|
52606
52928
|
return;
|
|
52607
52929
|
}
|
|
@@ -52629,7 +52951,7 @@ class AlphaTabApiBase {
|
|
|
52629
52951
|
this._previousCursorCache = cache;
|
|
52630
52952
|
this._previousStateForCursor = this._player.state;
|
|
52631
52953
|
this.uiFacade.beginInvoke(() => {
|
|
52632
|
-
this._internalCursorUpdateBeat(
|
|
52954
|
+
this._internalCursorUpdateBeat(lookupResult, stop, cache, beatBoundings, shouldScroll, cursorSpeed);
|
|
52633
52955
|
});
|
|
52634
52956
|
}
|
|
52635
52957
|
/**
|
|
@@ -52646,24 +52968,30 @@ class AlphaTabApiBase {
|
|
|
52646
52968
|
}
|
|
52647
52969
|
}
|
|
52648
52970
|
}
|
|
52649
|
-
_internalCursorUpdateBeat(
|
|
52650
|
-
const
|
|
52971
|
+
_internalCursorUpdateBeat(lookupResult, stop, boundsLookup, beatBoundings, shouldScroll, cursorSpeed) {
|
|
52972
|
+
const beat = lookupResult.beat;
|
|
52973
|
+
const nextBeat = lookupResult.nextBeat?.beat;
|
|
52974
|
+
let duration = lookupResult.duration;
|
|
52975
|
+
const beatsToHighlight = lookupResult.beatLookup.highlightedBeats;
|
|
52976
|
+
const cursorMode = lookupResult.cursorMode;
|
|
52977
|
+
const cursorHandler = this.customCursorHandler ?? this._defaultCursorHandler;
|
|
52651
52978
|
const beatCursor = this._beatCursor;
|
|
52979
|
+
const barCursor = this._barCursor;
|
|
52652
52980
|
const barBoundings = beatBoundings.barBounds.masterBarBounds;
|
|
52653
52981
|
const barBounds = barBoundings.visualBounds;
|
|
52654
52982
|
const previousBeatBounds = this._currentBeatBounds;
|
|
52655
52983
|
this._currentBeatBounds = beatBoundings;
|
|
52656
52984
|
if (barCursor) {
|
|
52657
|
-
|
|
52985
|
+
cursorHandler.placeBarCursor(barCursor, beatBoundings);
|
|
52658
52986
|
}
|
|
52659
52987
|
const isPlayingUpdate = this._player.state === PlayerState.Playing && !stop;
|
|
52660
|
-
let nextBeatX =
|
|
52988
|
+
let nextBeatX = beatBoundings.realBounds.x + beatBoundings.realBounds.w;
|
|
52661
52989
|
let nextBeatBoundings = null;
|
|
52662
52990
|
// get position of next beat on same system
|
|
52663
52991
|
if (nextBeat && cursorMode === MidiTickLookupFindBeatResultCursorMode.ToNextBext) {
|
|
52664
52992
|
// if we are moving within the same bar or to the next bar
|
|
52665
52993
|
// transition to the next beat, otherwise transition to the end of the bar.
|
|
52666
|
-
nextBeatBoundings =
|
|
52994
|
+
nextBeatBoundings = boundsLookup.findBeat(nextBeat);
|
|
52667
52995
|
if (nextBeatBoundings &&
|
|
52668
52996
|
nextBeatBoundings.barBounds.masterBarBounds.staffSystemBounds === barBoundings.staffSystemBounds) {
|
|
52669
52997
|
nextBeatX = nextBeatBoundings.onNotesX;
|
|
@@ -52671,48 +52999,30 @@ class AlphaTabApiBase {
|
|
|
52671
52999
|
}
|
|
52672
53000
|
let startBeatX = beatBoundings.onNotesX;
|
|
52673
53001
|
if (beatCursor) {
|
|
52674
|
-
|
|
52675
|
-
|
|
52676
|
-
|
|
52677
|
-
|
|
52678
|
-
|
|
52679
|
-
|
|
52680
|
-
|
|
52681
|
-
|
|
52682
|
-
|
|
52683
|
-
|
|
52684
|
-
|
|
52685
|
-
|
|
52686
|
-
|
|
52687
|
-
|
|
52688
|
-
|
|
52689
|
-
|
|
52690
|
-
|
|
52691
|
-
|
|
52692
|
-
|
|
52693
|
-
|
|
52694
|
-
// beatCursor!.transitionToX((duration / cursorSpeed), nextBeatX);
|
|
52695
|
-
const factor = cursorMode === MidiTickLookupFindBeatResultCursorMode.ToNextBext ? 2 : 1;
|
|
52696
|
-
nextBeatX = startBeatX + (nextBeatX - startBeatX) * factor;
|
|
52697
|
-
duration = (duration / cursorSpeed) * factor;
|
|
52698
|
-
// we need to put the transition to an own animation frame
|
|
52699
|
-
// otherwise the stop animation above is not applied.
|
|
52700
|
-
this.uiFacade.beginInvoke(() => {
|
|
52701
|
-
beatCursor.transitionToX(duration, nextBeatX);
|
|
52702
|
-
});
|
|
52703
|
-
}
|
|
52704
|
-
else {
|
|
52705
|
-
duration = 0;
|
|
52706
|
-
beatCursor.transitionToX(duration, nextBeatX);
|
|
52707
|
-
beatCursor.setBounds(startBeatX, barBounds.y, 1, barBounds.h);
|
|
52708
|
-
}
|
|
53002
|
+
const animationWidth = nextBeatX - beatBoundings.onNotesX;
|
|
53003
|
+
const relativePosition = this._previousTick - this._currentBeat.start;
|
|
53004
|
+
const ratioPosition = this._currentBeat.tickDuration > 0 ? relativePosition / this._currentBeat.tickDuration : 0;
|
|
53005
|
+
startBeatX = beatBoundings.onNotesX + animationWidth * ratioPosition;
|
|
53006
|
+
duration -= duration * ratioPosition;
|
|
53007
|
+
// respect speed
|
|
53008
|
+
duration = duration / cursorSpeed;
|
|
53009
|
+
if (isPlayingUpdate) {
|
|
53010
|
+
// we do not "reset" the cursor if we are smoothly moving from left to right.
|
|
53011
|
+
const jumpCursor = !previousBeatBounds ||
|
|
53012
|
+
this._isInitialBeatCursorUpdate ||
|
|
53013
|
+
barBounds.y !== previousBeatBounds.barBounds.masterBarBounds.visualBounds.y ||
|
|
53014
|
+
startBeatX < previousBeatBounds.onNotesX ||
|
|
53015
|
+
barBoundings.index > previousBeatBounds.barBounds.masterBarBounds.index + 1;
|
|
53016
|
+
if (jumpCursor) {
|
|
53017
|
+
cursorHandler.placeBeatCursor(beatCursor, beatBoundings, startBeatX);
|
|
53018
|
+
}
|
|
53019
|
+
this.uiFacade.beginInvoke(() => {
|
|
53020
|
+
cursorHandler.transitionBeatCursor(beatCursor, beatBoundings, startBeatX, nextBeatX, duration, cursorMode);
|
|
53021
|
+
});
|
|
52709
53022
|
}
|
|
52710
53023
|
else {
|
|
52711
|
-
// ticking cursor
|
|
52712
53024
|
duration = 0;
|
|
52713
|
-
|
|
52714
|
-
beatCursor.transitionToX(duration, nextBeatX);
|
|
52715
|
-
beatCursor.setBounds(startBeatX, barBounds.y, 1, barBounds.h);
|
|
53025
|
+
cursorHandler.placeBeatCursor(beatCursor, beatBoundings, startBeatX);
|
|
52716
53026
|
}
|
|
52717
53027
|
this._isInitialBeatCursorUpdate = false;
|
|
52718
53028
|
}
|
|
@@ -55589,42 +55899,6 @@ class AlphaTabWorkerScoreRenderer {
|
|
|
55589
55899
|
error = new EventEmitterOfT();
|
|
55590
55900
|
}
|
|
55591
55901
|
|
|
55592
|
-
/**
|
|
55593
|
-
* This wrapper holds all cursor related elements.
|
|
55594
|
-
* @public
|
|
55595
|
-
*/
|
|
55596
|
-
class Cursors {
|
|
55597
|
-
/**
|
|
55598
|
-
* Gets the element that spans across the whole music sheet and holds the other cursor elements.
|
|
55599
|
-
*/
|
|
55600
|
-
cursorWrapper;
|
|
55601
|
-
/**
|
|
55602
|
-
* Gets the element that is positioned above the bar that is currently played.
|
|
55603
|
-
*/
|
|
55604
|
-
barCursor;
|
|
55605
|
-
/**
|
|
55606
|
-
* Gets the element that is positioned above the beat that is currently played.
|
|
55607
|
-
*/
|
|
55608
|
-
beatCursor;
|
|
55609
|
-
/**
|
|
55610
|
-
* Gets the element that spans across the whole music sheet and will hold any selection related elements.
|
|
55611
|
-
*/
|
|
55612
|
-
selectionWrapper;
|
|
55613
|
-
/**
|
|
55614
|
-
* Initializes a new instance of the {@link Cursors} class.
|
|
55615
|
-
* @param cursorWrapper
|
|
55616
|
-
* @param barCursor
|
|
55617
|
-
* @param beatCursor
|
|
55618
|
-
* @param selectionWrapper
|
|
55619
|
-
*/
|
|
55620
|
-
constructor(cursorWrapper, barCursor, beatCursor, selectionWrapper) {
|
|
55621
|
-
this.cursorWrapper = cursorWrapper;
|
|
55622
|
-
this.barCursor = barCursor;
|
|
55623
|
-
this.beatCursor = beatCursor;
|
|
55624
|
-
this.selectionWrapper = selectionWrapper;
|
|
55625
|
-
}
|
|
55626
|
-
}
|
|
55627
|
-
|
|
55628
55902
|
/**
|
|
55629
55903
|
* An IContainer implementation which can be used for cursors and select ranges
|
|
55630
55904
|
* where browser scaling is relevant.
|
|
@@ -59928,11 +60202,12 @@ class NumberedKeySignatureGlyph extends EffectGlyph {
|
|
|
59928
60202
|
}
|
|
59929
60203
|
doLayout() {
|
|
59930
60204
|
super.doLayout();
|
|
59931
|
-
|
|
60205
|
+
let text = '';
|
|
59932
60206
|
let text2 = '';
|
|
59933
60207
|
let accidental = AccidentalType.None;
|
|
59934
60208
|
switch (this._keySignatureType) {
|
|
59935
60209
|
case KeySignatureType.Major:
|
|
60210
|
+
text = '1 = ';
|
|
59936
60211
|
switch (this._keySignature) {
|
|
59937
60212
|
case KeySignature.Cb:
|
|
59938
60213
|
text2 = ' C';
|
|
@@ -59996,6 +60271,7 @@ class NumberedKeySignatureGlyph extends EffectGlyph {
|
|
|
59996
60271
|
}
|
|
59997
60272
|
break;
|
|
59998
60273
|
case KeySignatureType.Minor:
|
|
60274
|
+
text = '6 = ';
|
|
59999
60275
|
switch (this._keySignature) {
|
|
60000
60276
|
case KeySignature.Cb:
|
|
60001
60277
|
text2 = ' a';
|
|
@@ -67975,7 +68251,6 @@ class SpacingGlyph extends Glyph {
|
|
|
67975
68251
|
* @internal
|
|
67976
68252
|
*/
|
|
67977
68253
|
class NumberedBeatPreNotesGlyph extends BeatGlyphBase {
|
|
67978
|
-
isNaturalizeAccidental = false;
|
|
67979
68254
|
accidental = AccidentalType.None;
|
|
67980
68255
|
skipLayout = false;
|
|
67981
68256
|
get effectElement() {
|
|
@@ -67990,25 +68265,25 @@ class NumberedBeatPreNotesGlyph extends BeatGlyphBase {
|
|
|
67990
68265
|
accidentals.renderer = this.renderer;
|
|
67991
68266
|
if (this.container.beat.notes.length > 0) {
|
|
67992
68267
|
const note = this.container.beat.notes[0];
|
|
67993
|
-
|
|
67994
|
-
|
|
67995
|
-
|
|
67996
|
-
|
|
67997
|
-
|
|
67998
|
-
|
|
67999
|
-
|
|
68000
|
-
|
|
68001
|
-
|
|
68002
|
-
|
|
68003
|
-
|
|
68004
|
-
|
|
68005
|
-
|
|
68006
|
-
|
|
68007
|
-
|
|
68008
|
-
|
|
68009
|
-
|
|
68010
|
-
|
|
68011
|
-
|
|
68268
|
+
const spelling = ModelUtils.resolveSpelling(this.renderer.bar.keySignature, note.displayValue, note.accidentalMode);
|
|
68269
|
+
const ksOffset = ModelUtils.getKeySignatureAccidentalOffset(this.renderer.bar.keySignature, spelling.degree);
|
|
68270
|
+
const requiredOffset = spelling.accidentalOffset - ksOffset;
|
|
68271
|
+
let accidentalToSet = AccidentalType.None;
|
|
68272
|
+
if (note.accidentalMode !== NoteAccidentalMode.ForceNone) {
|
|
68273
|
+
if (note.hasQuarterToneOffset) {
|
|
68274
|
+
if (requiredOffset > 0) {
|
|
68275
|
+
accidentalToSet = AccidentalType.SharpQuarterNoteUp;
|
|
68276
|
+
}
|
|
68277
|
+
else if (requiredOffset < 0) {
|
|
68278
|
+
accidentalToSet = AccidentalType.FlatQuarterNoteUp;
|
|
68279
|
+
}
|
|
68280
|
+
else {
|
|
68281
|
+
accidentalToSet = AccidentalType.NaturalQuarterNoteUp;
|
|
68282
|
+
}
|
|
68283
|
+
}
|
|
68284
|
+
else if (requiredOffset !== 0) {
|
|
68285
|
+
accidentalToSet = ModelUtils.accidentalOffsetToType(requiredOffset);
|
|
68286
|
+
}
|
|
68012
68287
|
}
|
|
68013
68288
|
// do we need an accidental on the note?
|
|
68014
68289
|
if (accidentalToSet !== AccidentalType.None) {
|
|
@@ -68115,21 +68390,21 @@ class NumberedBeatGlyph extends BeatOnNoteGlyphBase {
|
|
|
68115
68390
|
}
|
|
68116
68391
|
return 0;
|
|
68117
68392
|
}
|
|
68118
|
-
static
|
|
68119
|
-
// Flats
|
|
68120
|
-
59, 66, 61, 68, 63,
|
|
68121
|
-
// natural
|
|
68393
|
+
static _majorKeySignatureOneValues = [
|
|
68394
|
+
// Flats: Cb, Gb, Db, Ab, Eb, Bb, F
|
|
68395
|
+
59, 66, 61, 68, 63, 70, 65,
|
|
68396
|
+
// natural: C
|
|
68122
68397
|
60,
|
|
68123
|
-
// sharps
|
|
68398
|
+
// sharps: G, D, A, E, B, F#, C#
|
|
68124
68399
|
67, 62, 69, 64, 71, 66, 61
|
|
68125
68400
|
];
|
|
68126
|
-
static
|
|
68127
|
-
// Flats
|
|
68128
|
-
|
|
68129
|
-
// natural
|
|
68130
|
-
|
|
68131
|
-
// sharps
|
|
68132
|
-
|
|
68401
|
+
static _minorKeySignatureOneValues = [
|
|
68402
|
+
// Flats: Ab, Eb, Bb, F, C, G, D
|
|
68403
|
+
68, 63, 70, 65, 60, 67, 62,
|
|
68404
|
+
// natural: A
|
|
68405
|
+
69,
|
|
68406
|
+
// sharps: E, B, F#, C#, G#, D#, A#
|
|
68407
|
+
64, 71, 66, 61, 68, 63, 70
|
|
68133
68408
|
];
|
|
68134
68409
|
doLayout() {
|
|
68135
68410
|
// create glyphs
|
|
@@ -68143,38 +68418,26 @@ class NumberedBeatGlyph extends BeatOnNoteGlyphBase {
|
|
|
68143
68418
|
let numberWithinOctave = '0';
|
|
68144
68419
|
if (this.container.beat.notes.length > 0) {
|
|
68145
68420
|
const note = this.container.beat.notes[0];
|
|
68146
|
-
const kst = this.renderer.bar.keySignatureType;
|
|
68147
|
-
const ks = this.renderer.bar.keySignature;
|
|
68148
|
-
const ksi = ks + 7;
|
|
68149
|
-
const oneNoteValues = kst === KeySignatureType.Minor
|
|
68150
|
-
? NumberedBeatGlyph.minorKeySignatureOneValues
|
|
68151
|
-
: NumberedBeatGlyph.majorKeySignatureOneValues;
|
|
68152
|
-
const oneNoteValue = oneNoteValues[ksi];
|
|
68153
68421
|
if (note.isDead) {
|
|
68154
68422
|
numberWithinOctave = 'X';
|
|
68155
68423
|
}
|
|
68156
68424
|
else {
|
|
68425
|
+
const ks = this.renderer.bar.keySignature;
|
|
68426
|
+
const kst = this.renderer.bar.keySignatureType;
|
|
68427
|
+
const ksi = ks + 7;
|
|
68428
|
+
const oneNoteValues = kst === KeySignatureType.Minor
|
|
68429
|
+
? NumberedBeatGlyph._minorKeySignatureOneValues
|
|
68430
|
+
: NumberedBeatGlyph._majorKeySignatureOneValues;
|
|
68431
|
+
const oneNoteValue = oneNoteValues[ksi];
|
|
68432
|
+
const spelling = ModelUtils.resolveSpelling(ks, note.displayValue, note.accidentalMode);
|
|
68433
|
+
const tonicDegree = ModelUtils.getKeySignatureTonicDegree(ks, kst);
|
|
68434
|
+
const effectiveTonic = kst === KeySignatureType.Minor
|
|
68435
|
+
? (tonicDegree + 2) % 7 // relative major
|
|
68436
|
+
: tonicDegree;
|
|
68437
|
+
const degreeDistance = (spelling.degree - effectiveTonic + 7) % 7;
|
|
68438
|
+
numberWithinOctave = (degreeDistance + 1).toString();
|
|
68157
68439
|
const noteValue = note.displayValue - oneNoteValue;
|
|
68158
|
-
|
|
68159
|
-
octaveDots = noteValue < 0 ? ((Math.abs(noteValue) + 12) / 12) | 0 : (noteValue / 12) | 0;
|
|
68160
|
-
if (noteValue < 0) {
|
|
68161
|
-
octaveDots *= -1;
|
|
68162
|
-
}
|
|
68163
|
-
const stepList = ModelUtils.keySignatureIsSharp(ks) || ModelUtils.keySignatureIsNatural(ks)
|
|
68164
|
-
? AccidentalHelper.flatNoteSteps
|
|
68165
|
-
: AccidentalHelper.sharpNoteSteps;
|
|
68166
|
-
let steps = stepList[index] + 1;
|
|
68167
|
-
const hasAccidental = ModelUtils.accidentalNotes[index];
|
|
68168
|
-
if (hasAccidental &&
|
|
68169
|
-
!this.container.preNotes.isNaturalizeAccidental) {
|
|
68170
|
-
if (ksi < 7) {
|
|
68171
|
-
steps++;
|
|
68172
|
-
}
|
|
68173
|
-
else {
|
|
68174
|
-
steps--;
|
|
68175
|
-
}
|
|
68176
|
-
}
|
|
68177
|
-
numberWithinOctave = steps.toString();
|
|
68440
|
+
octaveDots = Math.floor(noteValue / 12);
|
|
68178
68441
|
}
|
|
68179
68442
|
}
|
|
68180
68443
|
if (this.container.beat.deadSlapped) {
|