@coderline/alphatab 1.8.0-alpha.1656 → 1.8.0-alpha.1667
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 +3 -3
- package/dist/alphaTab.core.mjs +1048 -735
- package/dist/alphaTab.d.ts +84 -4
- package/dist/alphaTab.js +1048 -735
- package/dist/alphaTab.min.js +3 -3
- package/dist/alphaTab.min.mjs +2 -2
- package/dist/alphaTab.mjs +2 -2
- package/dist/alphaTab.worker.min.mjs +2 -2
- package/dist/alphaTab.worker.mjs +2 -2
- package/dist/alphaTab.worklet.min.mjs +2 -2
- package/dist/alphaTab.worklet.mjs +2 -2
- package/package.json +3 -3
package/dist/alphaTab.core.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* alphaTab v1.8.0-alpha.
|
|
2
|
+
* alphaTab v1.8.0-alpha.1667 (develop, build 1667)
|
|
3
3
|
*
|
|
4
|
-
* Copyright ©
|
|
4
|
+
* Copyright © 2026, Daniel Kuschny and Contributors, All rights reserved.
|
|
5
5
|
*
|
|
6
6
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
7
7
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
@@ -203,9 +203,9 @@ class AlphaTabError extends Error {
|
|
|
203
203
|
* @internal
|
|
204
204
|
*/
|
|
205
205
|
class VersionInfo {
|
|
206
|
-
static version = '1.8.0-alpha.
|
|
207
|
-
static date = '
|
|
208
|
-
static commit = '
|
|
206
|
+
static version = '1.8.0-alpha.1667';
|
|
207
|
+
static date = '2026-01-06T02:24:13.312Z';
|
|
208
|
+
static commit = '52bfad1512fe6b0ca977ecefc2e3b5943729385d';
|
|
209
209
|
static print(print) {
|
|
210
210
|
print(`alphaTab ${VersionInfo.version}`);
|
|
211
211
|
print(`commit: ${VersionInfo.commit}`);
|
|
@@ -4640,9 +4640,12 @@ var MusicFontSymbol;
|
|
|
4640
4640
|
MusicFontSymbol[MusicFontSymbol["TextTupletBracketStartLongStem"] = 57857] = "TextTupletBracketStartLongStem";
|
|
4641
4641
|
MusicFontSymbol[MusicFontSymbol["TextTuplet3LongStem"] = 57858] = "TextTuplet3LongStem";
|
|
4642
4642
|
MusicFontSymbol[MusicFontSymbol["TextTupletBracketEndLongStem"] = 57859] = "TextTupletBracketEndLongStem";
|
|
4643
|
-
MusicFontSymbol[MusicFontSymbol["Tremolo3"] = 57890] = "Tremolo3";
|
|
4644
|
-
MusicFontSymbol[MusicFontSymbol["Tremolo2"] = 57889] = "Tremolo2";
|
|
4645
4643
|
MusicFontSymbol[MusicFontSymbol["Tremolo1"] = 57888] = "Tremolo1";
|
|
4644
|
+
MusicFontSymbol[MusicFontSymbol["Tremolo2"] = 57889] = "Tremolo2";
|
|
4645
|
+
MusicFontSymbol[MusicFontSymbol["Tremolo3"] = 57890] = "Tremolo3";
|
|
4646
|
+
MusicFontSymbol[MusicFontSymbol["Tremolo4"] = 57891] = "Tremolo4";
|
|
4647
|
+
MusicFontSymbol[MusicFontSymbol["Tremolo5"] = 57892] = "Tremolo5";
|
|
4648
|
+
MusicFontSymbol[MusicFontSymbol["BuzzRoll"] = 57898] = "BuzzRoll";
|
|
4646
4649
|
MusicFontSymbol[MusicFontSymbol["Flag8thUp"] = 57920] = "Flag8thUp";
|
|
4647
4650
|
MusicFontSymbol[MusicFontSymbol["Flag8thDown"] = 57921] = "Flag8thDown";
|
|
4648
4651
|
MusicFontSymbol[MusicFontSymbol["Flag16thUp"] = 57922] = "Flag16thUp";
|
|
@@ -6949,6 +6952,61 @@ var Rasgueado;
|
|
|
6949
6952
|
Rasgueado[Rasgueado["Peami"] = 18] = "Peami";
|
|
6950
6953
|
})(Rasgueado || (Rasgueado = {}));
|
|
6951
6954
|
|
|
6955
|
+
/**
|
|
6956
|
+
* The style of tremolo affecting mainly the display of the effect.
|
|
6957
|
+
* @public
|
|
6958
|
+
*/
|
|
6959
|
+
var TremoloPickingStyle;
|
|
6960
|
+
(function (TremoloPickingStyle) {
|
|
6961
|
+
/**
|
|
6962
|
+
* A classic tremolo expressed by diagonal bars on the stem.
|
|
6963
|
+
*/
|
|
6964
|
+
TremoloPickingStyle[TremoloPickingStyle["Default"] = 0] = "Default";
|
|
6965
|
+
/**
|
|
6966
|
+
* A buzz roll tremolo expressed by a 'z' shaped symbol.
|
|
6967
|
+
*/
|
|
6968
|
+
TremoloPickingStyle[TremoloPickingStyle["BuzzRoll"] = 1] = "BuzzRoll";
|
|
6969
|
+
})(TremoloPickingStyle || (TremoloPickingStyle = {}));
|
|
6970
|
+
/**
|
|
6971
|
+
* Describes a tremolo picking effect.
|
|
6972
|
+
* @json
|
|
6973
|
+
* @json_strict
|
|
6974
|
+
* @cloneable
|
|
6975
|
+
* @public
|
|
6976
|
+
*/
|
|
6977
|
+
class TremoloPickingEffect {
|
|
6978
|
+
/**
|
|
6979
|
+
* The minimum number of marks for the tremolo picking effect to be valid.
|
|
6980
|
+
*/
|
|
6981
|
+
static minMarks = 0;
|
|
6982
|
+
/**
|
|
6983
|
+
* The max number of marks for the tremolo picking effect to be valid.
|
|
6984
|
+
*/
|
|
6985
|
+
static maxMarks = 5;
|
|
6986
|
+
/**
|
|
6987
|
+
* The number of marks for the tremolo.
|
|
6988
|
+
* A mark is equal to a single bar shown for a default tremolos.
|
|
6989
|
+
*/
|
|
6990
|
+
marks = 0;
|
|
6991
|
+
/**
|
|
6992
|
+
* The style of the tremolo picking.
|
|
6993
|
+
*/
|
|
6994
|
+
style = TremoloPickingStyle.Default;
|
|
6995
|
+
/**
|
|
6996
|
+
* The number of marks define the note value of the note repetition.
|
|
6997
|
+
* e.g. a single mark is an 8th note.
|
|
6998
|
+
*/
|
|
6999
|
+
get duration() {
|
|
7000
|
+
let marks = this.marks;
|
|
7001
|
+
if (marks < 1) {
|
|
7002
|
+
marks = 1;
|
|
7003
|
+
}
|
|
7004
|
+
const baseDuration = Duration.Eighth;
|
|
7005
|
+
const actualDuration = baseDuration * Math.pow(2, marks);
|
|
7006
|
+
return actualDuration;
|
|
7007
|
+
}
|
|
7008
|
+
}
|
|
7009
|
+
|
|
6952
7010
|
/**
|
|
6953
7011
|
* Lists the different modes on how beaming for a beat should be done.
|
|
6954
7012
|
* @public
|
|
@@ -7371,13 +7429,59 @@ class Beat {
|
|
|
7371
7429
|
* Gets or sets the pickstroke applied on this beat.
|
|
7372
7430
|
*/
|
|
7373
7431
|
pickStroke = PickStroke.None;
|
|
7432
|
+
/**
|
|
7433
|
+
* Whether this beat has a tremolo picking effect.
|
|
7434
|
+
*/
|
|
7374
7435
|
get isTremolo() {
|
|
7375
|
-
return
|
|
7436
|
+
return this.tremoloPicking !== undefined;
|
|
7437
|
+
}
|
|
7438
|
+
/**
|
|
7439
|
+
* The tremolo picking effect.
|
|
7440
|
+
*/
|
|
7441
|
+
tremoloPicking;
|
|
7442
|
+
/**
|
|
7443
|
+
* The speed of the tremolo.
|
|
7444
|
+
* @deprecated Set {@link tremoloPicking} instead.
|
|
7445
|
+
*/
|
|
7446
|
+
get tremoloSpeed() {
|
|
7447
|
+
const tremolo = this.tremoloPicking;
|
|
7448
|
+
if (tremolo) {
|
|
7449
|
+
return tremolo.duration;
|
|
7450
|
+
}
|
|
7451
|
+
return null;
|
|
7376
7452
|
}
|
|
7377
7453
|
/**
|
|
7378
|
-
*
|
|
7454
|
+
* The speed of the tremolo.
|
|
7455
|
+
* @deprecated Set {@link tremoloPicking} instead.
|
|
7379
7456
|
*/
|
|
7380
|
-
tremoloSpeed
|
|
7457
|
+
set tremoloSpeed(value) {
|
|
7458
|
+
if (value === null) {
|
|
7459
|
+
this.tremoloPicking = undefined;
|
|
7460
|
+
return;
|
|
7461
|
+
}
|
|
7462
|
+
let effect = this.tremoloPicking;
|
|
7463
|
+
if (effect === undefined) {
|
|
7464
|
+
effect = new TremoloPickingEffect();
|
|
7465
|
+
this.tremoloPicking = effect;
|
|
7466
|
+
}
|
|
7467
|
+
switch (value) {
|
|
7468
|
+
case Duration.Eighth:
|
|
7469
|
+
effect.marks = 1;
|
|
7470
|
+
break;
|
|
7471
|
+
case Duration.Sixteenth:
|
|
7472
|
+
effect.marks = 2;
|
|
7473
|
+
break;
|
|
7474
|
+
case Duration.ThirtySecond:
|
|
7475
|
+
effect.marks = 3;
|
|
7476
|
+
break;
|
|
7477
|
+
case Duration.SixtyFourth:
|
|
7478
|
+
effect.marks = 4;
|
|
7479
|
+
break;
|
|
7480
|
+
case Duration.OneHundredTwentyEighth:
|
|
7481
|
+
effect.marks = 5;
|
|
7482
|
+
break;
|
|
7483
|
+
}
|
|
7484
|
+
}
|
|
7381
7485
|
/**
|
|
7382
7486
|
* Gets or sets whether a crescendo/decrescendo is applied on this beat.
|
|
7383
7487
|
*/
|
|
@@ -7672,6 +7776,12 @@ class Beat {
|
|
|
7672
7776
|
if (this.brushType === BrushType.None) {
|
|
7673
7777
|
this.brushDuration = 0;
|
|
7674
7778
|
}
|
|
7779
|
+
const tremolo = this.tremoloPicking;
|
|
7780
|
+
if (tremolo !== undefined) {
|
|
7781
|
+
if (tremolo.marks < TremoloPickingEffect.minMarks || tremolo.marks > TremoloPickingEffect.maxMarks) {
|
|
7782
|
+
this.tremoloPicking = undefined;
|
|
7783
|
+
}
|
|
7784
|
+
}
|
|
7675
7785
|
const displayMode = !settings ? NotationMode.GuitarPro : settings.notation.notationMode;
|
|
7676
7786
|
let isGradual = this.text === 'grad' || this.text === 'grad.';
|
|
7677
7787
|
if (isGradual && displayMode === NotationMode.SongBook) {
|
|
@@ -8080,6 +8190,23 @@ class AutomationCloner {
|
|
|
8080
8190
|
}
|
|
8081
8191
|
}
|
|
8082
8192
|
|
|
8193
|
+
// <auto-generated>
|
|
8194
|
+
// This code was auto-generated.
|
|
8195
|
+
// Changes to this file may cause incorrect behavior and will be lost if
|
|
8196
|
+
// the code is regenerated.
|
|
8197
|
+
// </auto-generated>
|
|
8198
|
+
/**
|
|
8199
|
+
* @internal
|
|
8200
|
+
*/
|
|
8201
|
+
class TremoloPickingEffectCloner {
|
|
8202
|
+
static clone(original) {
|
|
8203
|
+
const clone = new TremoloPickingEffect();
|
|
8204
|
+
clone.marks = original.marks;
|
|
8205
|
+
clone.style = original.style;
|
|
8206
|
+
return clone;
|
|
8207
|
+
}
|
|
8208
|
+
}
|
|
8209
|
+
|
|
8083
8210
|
// <auto-generated>
|
|
8084
8211
|
// This code was auto-generated.
|
|
8085
8212
|
// Changes to this file may cause incorrect behavior and will be lost if
|
|
@@ -8132,7 +8259,7 @@ class BeatCloner {
|
|
|
8132
8259
|
clone.chordId = original.chordId;
|
|
8133
8260
|
clone.graceType = original.graceType;
|
|
8134
8261
|
clone.pickStroke = original.pickStroke;
|
|
8135
|
-
clone.
|
|
8262
|
+
clone.tremoloPicking = original.tremoloPicking ? TremoloPickingEffectCloner.clone(original.tremoloPicking) : undefined;
|
|
8136
8263
|
clone.crescendo = original.crescendo;
|
|
8137
8264
|
clone.displayStart = original.displayStart;
|
|
8138
8265
|
clone.playbackStart = original.playbackStart;
|
|
@@ -8515,6 +8642,11 @@ class AlphaTex1EnumMappings {
|
|
|
8515
8642
|
['dadoublecoda', 18]
|
|
8516
8643
|
]);
|
|
8517
8644
|
static directionReversed = AlphaTex1EnumMappings._reverse(AlphaTex1EnumMappings.direction);
|
|
8645
|
+
static tremoloPickingStyle = new Map([
|
|
8646
|
+
['default', 0],
|
|
8647
|
+
['buzzroll', 1]
|
|
8648
|
+
]);
|
|
8649
|
+
static tremoloPickingStyleReversed = AlphaTex1EnumMappings._reverse(AlphaTex1EnumMappings.tremoloPickingStyle);
|
|
8518
8650
|
static keySignaturesMinorReversed = new Map([
|
|
8519
8651
|
[-7, 'abminor'],
|
|
8520
8652
|
[-6, 'ebminor'],
|
|
@@ -9275,7 +9407,15 @@ class AlphaTex1LanguageDefinitions {
|
|
|
9275
9407
|
],
|
|
9276
9408
|
['volume', [[[[16], 0]]]],
|
|
9277
9409
|
['balance', [[[[16], 0]]]],
|
|
9278
|
-
[
|
|
9410
|
+
[
|
|
9411
|
+
'tp',
|
|
9412
|
+
[
|
|
9413
|
+
[
|
|
9414
|
+
[[16], 0],
|
|
9415
|
+
[[10, 17], 1, ['default', 'buzzroll']]
|
|
9416
|
+
]
|
|
9417
|
+
]
|
|
9418
|
+
],
|
|
9279
9419
|
[
|
|
9280
9420
|
'barre',
|
|
9281
9421
|
[
|
|
@@ -15193,28 +15333,45 @@ class AlphaTex1LanguageHandler {
|
|
|
15193
15333
|
beat.automations.push(balanceAutomation);
|
|
15194
15334
|
return ApplyNodeResult.Applied;
|
|
15195
15335
|
case 'tp':
|
|
15196
|
-
|
|
15336
|
+
const tremolo = new TremoloPickingEffect();
|
|
15337
|
+
beat.tremoloPicking = tremolo;
|
|
15197
15338
|
if (p.arguments && p.arguments.arguments.length > 0) {
|
|
15198
|
-
|
|
15199
|
-
|
|
15200
|
-
|
|
15201
|
-
|
|
15202
|
-
|
|
15203
|
-
|
|
15204
|
-
|
|
15205
|
-
|
|
15206
|
-
|
|
15207
|
-
|
|
15208
|
-
|
|
15209
|
-
|
|
15210
|
-
|
|
15211
|
-
|
|
15212
|
-
|
|
15213
|
-
|
|
15214
|
-
|
|
15215
|
-
|
|
15216
|
-
|
|
15339
|
+
if (p.arguments.arguments.length > 0) {
|
|
15340
|
+
const tremoloMarks = p.arguments.arguments[0].value;
|
|
15341
|
+
if (tremoloMarks >= TremoloPickingEffect.minMarks &&
|
|
15342
|
+
tremoloMarks <= TremoloPickingEffect.maxMarks) {
|
|
15343
|
+
tremolo.marks = tremoloMarks;
|
|
15344
|
+
}
|
|
15345
|
+
else {
|
|
15346
|
+
switch (tremoloMarks) {
|
|
15347
|
+
// backwards compatibility
|
|
15348
|
+
case 8:
|
|
15349
|
+
tremolo.marks = 1;
|
|
15350
|
+
break;
|
|
15351
|
+
case 16:
|
|
15352
|
+
tremolo.marks = 2;
|
|
15353
|
+
break;
|
|
15354
|
+
case 32:
|
|
15355
|
+
tremolo.marks = 3;
|
|
15356
|
+
break;
|
|
15357
|
+
default:
|
|
15358
|
+
importer.addSemanticDiagnostic({
|
|
15359
|
+
code: AlphaTexDiagnosticCode.AT209,
|
|
15360
|
+
message: `Unexpected tremolo marks value '${tremoloMarks}, expected: ${TremoloPickingEffect.minMarks}-${TremoloPickingEffect.maxMarks}, or legacy: 8, 16 or 32`,
|
|
15361
|
+
severity: AlphaTexDiagnosticsSeverity.Error,
|
|
15362
|
+
start: p.arguments.arguments[0].start,
|
|
15363
|
+
end: p.arguments.arguments[0].end
|
|
15364
|
+
});
|
|
15365
|
+
return ApplyNodeResult.NotAppliedSemanticError;
|
|
15366
|
+
}
|
|
15367
|
+
}
|
|
15368
|
+
}
|
|
15369
|
+
if (p.arguments.arguments.length > 1) {
|
|
15370
|
+
const tremoloStyle = AlphaTex1LanguageHandler._parseEnumValue(importer, p.arguments, 'tremolo picking style', AlphaTex1EnumMappings.tremoloPickingStyle, 1);
|
|
15371
|
+
if (tremoloStyle === undefined) {
|
|
15217
15372
|
return ApplyNodeResult.NotAppliedSemanticError;
|
|
15373
|
+
}
|
|
15374
|
+
tremolo.style = tremoloStyle;
|
|
15218
15375
|
}
|
|
15219
15376
|
}
|
|
15220
15377
|
return ApplyNodeResult.Applied;
|
|
@@ -16421,7 +16578,11 @@ class AlphaTex1LanguageHandler {
|
|
|
16421
16578
|
: Atnf.identValue(AlphaTex1EnumMappings.graceTypeReversed.get(beat.graceType)));
|
|
16422
16579
|
}
|
|
16423
16580
|
if (beat.isTremolo) {
|
|
16424
|
-
|
|
16581
|
+
const values = [Atnf.number(beat.tremoloPicking.marks)];
|
|
16582
|
+
if (beat.tremoloPicking.style !== TremoloPickingStyle.Default) {
|
|
16583
|
+
values.push(Atnf.ident(TremoloPickingStyle[beat.tremoloPicking.style]));
|
|
16584
|
+
}
|
|
16585
|
+
Atnf.prop(properties, 'tp', Atnf.args(values));
|
|
16425
16586
|
}
|
|
16426
16587
|
switch (beat.crescendo) {
|
|
16427
16588
|
case CrescendoType.Crescendo:
|
|
@@ -16822,9 +16983,6 @@ class AlphaTexImporter extends ScoreImporter {
|
|
|
16822
16983
|
// even start translating when we have parser errors
|
|
16823
16984
|
// as long we have some nodes, we can already start semantically
|
|
16824
16985
|
// validating and using them
|
|
16825
|
-
if (scoreNode.bars.length === 0) {
|
|
16826
|
-
throw new UnsupportedFormatError('No alphaTex data found');
|
|
16827
|
-
}
|
|
16828
16986
|
this._bars(scoreNode);
|
|
16829
16987
|
if (this.semanticDiagnostics.hasErrors) {
|
|
16830
16988
|
if (this._state.hasAnyProperData) {
|
|
@@ -21445,18 +21603,9 @@ class Gp3To5Importer extends ScoreImporter {
|
|
|
21445
21603
|
graceBeat.addNote(graceNote);
|
|
21446
21604
|
}
|
|
21447
21605
|
readTremoloPicking(beat) {
|
|
21448
|
-
const
|
|
21449
|
-
|
|
21450
|
-
|
|
21451
|
-
beat.tremoloSpeed = Duration.Eighth;
|
|
21452
|
-
break;
|
|
21453
|
-
case 2:
|
|
21454
|
-
beat.tremoloSpeed = Duration.Sixteenth;
|
|
21455
|
-
break;
|
|
21456
|
-
case 3:
|
|
21457
|
-
beat.tremoloSpeed = Duration.ThirtySecond;
|
|
21458
|
-
break;
|
|
21459
|
-
}
|
|
21606
|
+
const effect = new TremoloPickingEffect();
|
|
21607
|
+
beat.tremoloPicking = effect;
|
|
21608
|
+
effect.marks = this.data.readByte();
|
|
21460
21609
|
}
|
|
21461
21610
|
readSlide(note) {
|
|
21462
21611
|
if (this._versionNumber >= 500) {
|
|
@@ -23703,15 +23852,17 @@ class GpifParser {
|
|
|
23703
23852
|
}
|
|
23704
23853
|
break;
|
|
23705
23854
|
case 'Tremolo':
|
|
23855
|
+
const tremolo = new TremoloPickingEffect();
|
|
23856
|
+
beat.tremoloPicking = tremolo;
|
|
23706
23857
|
switch (c.innerText) {
|
|
23707
23858
|
case '1/2':
|
|
23708
|
-
|
|
23859
|
+
tremolo.marks = 1;
|
|
23709
23860
|
break;
|
|
23710
23861
|
case '1/4':
|
|
23711
|
-
|
|
23862
|
+
tremolo.marks = 2;
|
|
23712
23863
|
break;
|
|
23713
23864
|
case '1/8':
|
|
23714
|
-
|
|
23865
|
+
tremolo.marks = 3;
|
|
23715
23866
|
break;
|
|
23716
23867
|
}
|
|
23717
23868
|
break;
|
|
@@ -28779,16 +28930,12 @@ class MusicXmlImporter extends ScoreImporter {
|
|
|
28779
28930
|
break;
|
|
28780
28931
|
// case 'schleifer': Not supported
|
|
28781
28932
|
case 'tremolo':
|
|
28782
|
-
|
|
28783
|
-
|
|
28784
|
-
|
|
28785
|
-
|
|
28786
|
-
|
|
28787
|
-
|
|
28788
|
-
break;
|
|
28789
|
-
case '3':
|
|
28790
|
-
note.beat.tremoloSpeed = Duration.ThirtySecond;
|
|
28791
|
-
break;
|
|
28933
|
+
const tremolo = new TremoloPickingEffect();
|
|
28934
|
+
note.beat.tremoloPicking = tremolo;
|
|
28935
|
+
tremolo.marks = Number.parseInt(c.innerText, 10);
|
|
28936
|
+
if ((c.getAttribute('type', '') === 'unmeasured' && tremolo.marks === 0) ||
|
|
28937
|
+
c.getAttribute('smufl', '') === 'buzzRoll') {
|
|
28938
|
+
tremolo.style = TremoloPickingStyle.BuzzRoll;
|
|
28792
28939
|
}
|
|
28793
28940
|
break;
|
|
28794
28941
|
// case 'haydn': Not supported
|
|
@@ -37899,6 +38046,38 @@ class NoteSerializer {
|
|
|
37899
38046
|
}
|
|
37900
38047
|
}
|
|
37901
38048
|
|
|
38049
|
+
/**
|
|
38050
|
+
* @internal
|
|
38051
|
+
*/
|
|
38052
|
+
class TremoloPickingEffectSerializer {
|
|
38053
|
+
static fromJson(obj, m) {
|
|
38054
|
+
if (!m) {
|
|
38055
|
+
return;
|
|
38056
|
+
}
|
|
38057
|
+
JsonHelper.forEach(m, (v, k) => TremoloPickingEffectSerializer.setProperty(obj, k, v));
|
|
38058
|
+
}
|
|
38059
|
+
static toJson(obj) {
|
|
38060
|
+
if (!obj) {
|
|
38061
|
+
return null;
|
|
38062
|
+
}
|
|
38063
|
+
const o = new Map();
|
|
38064
|
+
o.set("marks", obj.marks);
|
|
38065
|
+
o.set("style", obj.style);
|
|
38066
|
+
return o;
|
|
38067
|
+
}
|
|
38068
|
+
static setProperty(obj, property, v) {
|
|
38069
|
+
switch (property) {
|
|
38070
|
+
case "marks":
|
|
38071
|
+
obj.marks = v;
|
|
38072
|
+
return true;
|
|
38073
|
+
case "style":
|
|
38074
|
+
obj.style = JsonHelper.parseEnum(v, TremoloPickingStyle);
|
|
38075
|
+
return true;
|
|
38076
|
+
}
|
|
38077
|
+
return false;
|
|
38078
|
+
}
|
|
38079
|
+
}
|
|
38080
|
+
|
|
37902
38081
|
/**
|
|
37903
38082
|
* @internal
|
|
37904
38083
|
*/
|
|
@@ -37981,7 +38160,9 @@ class BeatSerializer {
|
|
|
37981
38160
|
o.set("chordid", obj.chordId);
|
|
37982
38161
|
o.set("gracetype", obj.graceType);
|
|
37983
38162
|
o.set("pickstroke", obj.pickStroke);
|
|
37984
|
-
|
|
38163
|
+
if (obj.tremoloPicking) {
|
|
38164
|
+
o.set("tremolopicking", TremoloPickingEffectSerializer.toJson(obj.tremoloPicking));
|
|
38165
|
+
}
|
|
37985
38166
|
o.set("crescendo", obj.crescendo);
|
|
37986
38167
|
o.set("displaystart", obj.displayStart);
|
|
37987
38168
|
o.set("playbackstart", obj.playbackStart);
|
|
@@ -38107,8 +38288,14 @@ class BeatSerializer {
|
|
|
38107
38288
|
case "pickstroke":
|
|
38108
38289
|
obj.pickStroke = JsonHelper.parseEnum(v, PickStroke);
|
|
38109
38290
|
return true;
|
|
38110
|
-
case "
|
|
38111
|
-
|
|
38291
|
+
case "tremolopicking":
|
|
38292
|
+
if (v) {
|
|
38293
|
+
obj.tremoloPicking = new TremoloPickingEffect();
|
|
38294
|
+
TremoloPickingEffectSerializer.fromJson(obj.tremoloPicking, v);
|
|
38295
|
+
}
|
|
38296
|
+
else {
|
|
38297
|
+
obj.tremoloPicking = undefined;
|
|
38298
|
+
}
|
|
38112
38299
|
return true;
|
|
38113
38300
|
case "crescendo":
|
|
38114
38301
|
obj.crescendo = JsonHelper.parseEnum(v, CrescendoType);
|
|
@@ -39422,6 +39609,7 @@ class EngravingSettingsCloner {
|
|
|
39422
39609
|
clone.tuningGlyphStringRowPadding = original.tuningGlyphStringRowPadding;
|
|
39423
39610
|
clone.directionsScale = original.directionsScale;
|
|
39424
39611
|
clone.multiVoiceDisplacedNoteHeadSpacing = original.multiVoiceDisplacedNoteHeadSpacing;
|
|
39612
|
+
clone.stemFlagHeight = new Map(original.stemFlagHeight);
|
|
39425
39613
|
return clone;
|
|
39426
39614
|
}
|
|
39427
39615
|
}
|
|
@@ -39733,6 +39921,20 @@ class EngravingSettings {
|
|
|
39733
39921
|
this.stemFlagOffsets.set(Duration.SixtyFourth, 0);
|
|
39734
39922
|
this.stemFlagOffsets.set(Duration.OneHundredTwentyEighth, 0);
|
|
39735
39923
|
this.stemFlagOffsets.set(Duration.TwoHundredFiftySixth, 0);
|
|
39924
|
+
// Workaround for: https://github.com/w3c/smufl/issues/203
|
|
39925
|
+
// There is no clear anchor for the height of flags on the stem side yet.
|
|
39926
|
+
// These aproximations are tested with bravura
|
|
39927
|
+
this.stemFlagHeight.set(Duration.QuadrupleWhole, 0);
|
|
39928
|
+
this.stemFlagHeight.set(Duration.DoubleWhole, 0);
|
|
39929
|
+
this.stemFlagHeight.set(Duration.Whole, 0);
|
|
39930
|
+
this.stemFlagHeight.set(Duration.Half, 0);
|
|
39931
|
+
this.stemFlagHeight.set(Duration.Quarter, 0);
|
|
39932
|
+
this.stemFlagHeight.set(Duration.Eighth, 1 * this.oneStaffSpace);
|
|
39933
|
+
this.stemFlagHeight.set(Duration.Sixteenth, 1.5 * this.oneStaffSpace);
|
|
39934
|
+
this.stemFlagHeight.set(Duration.ThirtySecond, 2 * this.oneStaffSpace);
|
|
39935
|
+
this.stemFlagHeight.set(Duration.SixtyFourth, 3 * this.oneStaffSpace);
|
|
39936
|
+
this.stemFlagHeight.set(Duration.OneHundredTwentyEighth, 3.5 * this.oneStaffSpace);
|
|
39937
|
+
this.stemFlagHeight.set(Duration.TwoHundredFiftySixth, 4.2 * this.oneStaffSpace);
|
|
39736
39938
|
for (const [g, v] of Object.entries(smufl.glyphsWithAnchors)) {
|
|
39737
39939
|
const symbol = EngravingSettings._smuflNameToMusicFontSymbol(g);
|
|
39738
39940
|
if (symbol) {
|
|
@@ -40079,6 +40281,19 @@ class EngravingSettings {
|
|
|
40079
40281
|
* in case of multi-voice note head overlaps.
|
|
40080
40282
|
*/
|
|
40081
40283
|
multiVoiceDisplacedNoteHeadSpacing = 0;
|
|
40284
|
+
/**
|
|
40285
|
+
* Calculates the stem height for a note of the given duration.
|
|
40286
|
+
* @param duration The duration to calculate the height respecting flag sizes.
|
|
40287
|
+
* @param hasFlag True if we need to respect flags, false if we have beams.
|
|
40288
|
+
* @returns The total stem height
|
|
40289
|
+
*/
|
|
40290
|
+
getStemLength(duration, hasFlag) {
|
|
40291
|
+
return this.standardStemLength + (hasFlag ? this.stemFlagOffsets.get(duration) : 0);
|
|
40292
|
+
}
|
|
40293
|
+
/**
|
|
40294
|
+
* The space needed by flags on the stem-side from top to bottom to place.
|
|
40295
|
+
*/
|
|
40296
|
+
stemFlagHeight = new Map();
|
|
40082
40297
|
// Idea: maybe we can encode and pack this large metadata into a more compact format (e.g. BSON or a custom binary blob?)
|
|
40083
40298
|
// This metadata below is updated automatically from the bravura_metadata.json via npm script
|
|
40084
40299
|
static bravuraMetadata =
|
|
@@ -40211,6 +40426,10 @@ class EngravingSettings {
|
|
|
40211
40426
|
bBoxNE: [1.876, 1.18],
|
|
40212
40427
|
bBoxSW: [0, 0]
|
|
40213
40428
|
},
|
|
40429
|
+
buzzRoll: {
|
|
40430
|
+
bBoxNE: [0.624, 0.464],
|
|
40431
|
+
bBoxSW: [-0.62, -0.464]
|
|
40432
|
+
},
|
|
40214
40433
|
cClef: {
|
|
40215
40434
|
bBoxNE: [2.796, 2.024],
|
|
40216
40435
|
bBoxSW: [0, -2.024]
|
|
@@ -41167,6 +41386,14 @@ class EngravingSettings {
|
|
|
41167
41386
|
bBoxNE: [0.6, 1.112],
|
|
41168
41387
|
bBoxSW: [-0.6, -1.12]
|
|
41169
41388
|
},
|
|
41389
|
+
tremolo4: {
|
|
41390
|
+
bBoxNE: [0.6, 1.496],
|
|
41391
|
+
bBoxSW: [-0.6, -1.48]
|
|
41392
|
+
},
|
|
41393
|
+
tremolo5: {
|
|
41394
|
+
bBoxNE: [0.6, 1.88],
|
|
41395
|
+
bBoxSW: [-0.604, -1.84]
|
|
41396
|
+
},
|
|
41170
41397
|
tuplet0: {
|
|
41171
41398
|
bBoxNE: [1.2731041262817027, 1.5],
|
|
41172
41399
|
bBoxSW: [-0.001204330173715796, -0.032]
|
|
@@ -41814,6 +42041,13 @@ class EngravingSettingsSerializer {
|
|
|
41814
42041
|
o.set("tuningglyphstringrowpadding", obj.tuningGlyphStringRowPadding);
|
|
41815
42042
|
o.set("directionsscale", obj.directionsScale);
|
|
41816
42043
|
o.set("multivoicedisplacednoteheadspacing", obj.multiVoiceDisplacedNoteHeadSpacing);
|
|
42044
|
+
{
|
|
42045
|
+
const m = new Map();
|
|
42046
|
+
o.set("stemflagheight", m);
|
|
42047
|
+
for (const [k, v] of obj.stemFlagHeight) {
|
|
42048
|
+
m.set(k.toString(), v);
|
|
42049
|
+
}
|
|
42050
|
+
}
|
|
41817
42051
|
return o;
|
|
41818
42052
|
}
|
|
41819
42053
|
static setProperty(obj, property, v) {
|
|
@@ -42095,6 +42329,12 @@ class EngravingSettingsSerializer {
|
|
|
42095
42329
|
case "multivoicedisplacednoteheadspacing":
|
|
42096
42330
|
obj.multiVoiceDisplacedNoteHeadSpacing = v;
|
|
42097
42331
|
return true;
|
|
42332
|
+
case "stemflagheight":
|
|
42333
|
+
obj.stemFlagHeight = new Map();
|
|
42334
|
+
JsonHelper.forEach(v, (v, k) => {
|
|
42335
|
+
obj.stemFlagHeight.set(JsonHelper.parseEnum(k, Duration), v);
|
|
42336
|
+
});
|
|
42337
|
+
return true;
|
|
42098
42338
|
}
|
|
42099
42339
|
return false;
|
|
42100
42340
|
}
|
|
@@ -48316,7 +48556,12 @@ class MidiFileGenerator {
|
|
|
48316
48556
|
}
|
|
48317
48557
|
_generateTremoloPicking(note, noteStart, noteDuration, noteKey, dynamicValue, channel) {
|
|
48318
48558
|
const track = note.beat.voice.bar.staff.track;
|
|
48319
|
-
|
|
48559
|
+
const marks = note.beat.tremoloPicking.marks;
|
|
48560
|
+
if (marks === 0) {
|
|
48561
|
+
return;
|
|
48562
|
+
}
|
|
48563
|
+
// the marks represent the duration
|
|
48564
|
+
let tpLength = MidiUtils.toTicks(note.beat.tremoloPicking.duration);
|
|
48320
48565
|
let tick = noteStart;
|
|
48321
48566
|
const end = noteStart + noteDuration.untilTieOrSlideEnd;
|
|
48322
48567
|
while (tick + 10 < end) {
|
|
@@ -48742,6 +48987,12 @@ class BeatContainerGlyph extends BeatContainerGlyphBase {
|
|
|
48742
48987
|
beat;
|
|
48743
48988
|
preNotes;
|
|
48744
48989
|
onNotes;
|
|
48990
|
+
getLowestNoteY(requestedPosition) {
|
|
48991
|
+
return this.onNotes.getLowestNoteY(requestedPosition);
|
|
48992
|
+
}
|
|
48993
|
+
getHighestNoteY(requestedPosition) {
|
|
48994
|
+
return this.onNotes.getHighestNoteY(requestedPosition);
|
|
48995
|
+
}
|
|
48745
48996
|
get beatId() {
|
|
48746
48997
|
return this.beat.id;
|
|
48747
48998
|
}
|
|
@@ -48805,7 +49056,7 @@ class BeatContainerGlyph extends BeatContainerGlyphBase {
|
|
|
48805
49056
|
return helper.hasFlag(false, undefined);
|
|
48806
49057
|
}
|
|
48807
49058
|
get postBeatStretch() {
|
|
48808
|
-
return
|
|
49059
|
+
return this.onNotes.computedWidth + this._tieWidth - this.onNotes.onTimeX;
|
|
48809
49060
|
}
|
|
48810
49061
|
registerLayoutingInfo(layoutings) {
|
|
48811
49062
|
const preBeatStretch = this.preNotes.computedWidth + this.onNotes.onTimeX;
|
|
@@ -60015,16 +60266,22 @@ class EffectBandContainer {
|
|
|
60015
60266
|
return false;
|
|
60016
60267
|
}
|
|
60017
60268
|
let y = 0;
|
|
60269
|
+
// TODO. activate padding
|
|
60270
|
+
// const paddingTop = this._isTopContainer ? 0 : this._renderer.settings.display.effectBandPaddingBottom;
|
|
60271
|
+
// const paddingBottom = this._isTopContainer ? this._renderer.settings.display.effectBandPaddingBottom : 0;
|
|
60272
|
+
const paddingTop = 0;
|
|
60273
|
+
const paddingBottom = this._renderer.settings.display.effectBandPaddingBottom;
|
|
60018
60274
|
for (const slot of this._effectBandSizingInfo.slots) {
|
|
60019
60275
|
slot.shared.y = y;
|
|
60020
60276
|
for (const band of slot.bands) {
|
|
60277
|
+
y += paddingTop;
|
|
60021
60278
|
band.y = y;
|
|
60022
60279
|
if (finalize) {
|
|
60023
60280
|
band.finalizeBand();
|
|
60024
60281
|
}
|
|
60025
60282
|
band.height = slot.shared.height;
|
|
60026
60283
|
}
|
|
60027
|
-
y += slot.shared.height +
|
|
60284
|
+
y += slot.shared.height + paddingBottom;
|
|
60028
60285
|
}
|
|
60029
60286
|
y = Math.ceil(y);
|
|
60030
60287
|
if (y !== this.height) {
|
|
@@ -60254,6 +60511,20 @@ class MultiVoiceContainerGlyph extends Glyph {
|
|
|
60254
60511
|
}
|
|
60255
60512
|
return 0;
|
|
60256
60513
|
}
|
|
60514
|
+
getLowestNoteY(beat, position) {
|
|
60515
|
+
const container = this.getBeatContainer(beat);
|
|
60516
|
+
if (container) {
|
|
60517
|
+
return container.y + container.getLowestNoteY(position);
|
|
60518
|
+
}
|
|
60519
|
+
return 0;
|
|
60520
|
+
}
|
|
60521
|
+
getHighestNoteY(beat, position) {
|
|
60522
|
+
const container = this.getBeatContainer(beat);
|
|
60523
|
+
if (container) {
|
|
60524
|
+
return container.y + container.getHighestNoteY(position);
|
|
60525
|
+
}
|
|
60526
|
+
return 0;
|
|
60527
|
+
}
|
|
60257
60528
|
getNoteX(note, requestedPosition) {
|
|
60258
60529
|
const container = this.getBeatContainer(note.beat);
|
|
60259
60530
|
if (container) {
|
|
@@ -60266,14 +60537,14 @@ class MultiVoiceContainerGlyph extends Glyph {
|
|
|
60266
60537
|
if (beat) {
|
|
60267
60538
|
return beat.y + beat.getNoteY(note, requestedPosition);
|
|
60268
60539
|
}
|
|
60269
|
-
return
|
|
60540
|
+
return 0;
|
|
60270
60541
|
}
|
|
60271
60542
|
getRestY(beat, requestedPosition) {
|
|
60272
60543
|
const container = this.getBeatContainer(beat);
|
|
60273
60544
|
if (container) {
|
|
60274
60545
|
return container.y + container.getRestY(requestedPosition);
|
|
60275
60546
|
}
|
|
60276
|
-
return
|
|
60547
|
+
return 0;
|
|
60277
60548
|
}
|
|
60278
60549
|
getBeatContainer(beat) {
|
|
60279
60550
|
if (!this._beatGlyphLookup.has(beat.id)) {
|
|
@@ -60943,16 +61214,18 @@ class MultiBarRestBeatContainerGlyph extends BeatContainerGlyphBase {
|
|
|
60943
61214
|
const g = this._glyph;
|
|
60944
61215
|
if (g) {
|
|
60945
61216
|
switch (requestedPosition) {
|
|
60946
|
-
case NoteYPosition.TopWithStem:
|
|
60947
61217
|
case NoteYPosition.Top:
|
|
60948
61218
|
return g.y;
|
|
61219
|
+
case NoteYPosition.TopWithStem:
|
|
61220
|
+
return g.y - this.renderer.smuflMetrics.getStemLength(Duration.Quarter, true);
|
|
60949
61221
|
case NoteYPosition.Center:
|
|
60950
61222
|
case NoteYPosition.StemUp:
|
|
60951
61223
|
case NoteYPosition.StemDown:
|
|
60952
61224
|
return g.y + g.height / 2;
|
|
60953
61225
|
case NoteYPosition.Bottom:
|
|
60954
|
-
case NoteYPosition.BottomWithStem:
|
|
60955
61226
|
return g.y + g.height;
|
|
61227
|
+
case NoteYPosition.BottomWithStem:
|
|
61228
|
+
return g.y + g.height + this.renderer.smuflMetrics.getStemLength(Duration.Quarter, true);
|
|
60956
61229
|
}
|
|
60957
61230
|
}
|
|
60958
61231
|
return 0;
|
|
@@ -60960,6 +61233,12 @@ class MultiBarRestBeatContainerGlyph extends BeatContainerGlyphBase {
|
|
|
60960
61233
|
getNoteY(_note, requestedPosition) {
|
|
60961
61234
|
return this.getRestY(requestedPosition);
|
|
60962
61235
|
}
|
|
61236
|
+
getHighestNoteY(position) {
|
|
61237
|
+
return this.getRestY(position);
|
|
61238
|
+
}
|
|
61239
|
+
getLowestNoteY(position) {
|
|
61240
|
+
return this.getRestY(position);
|
|
61241
|
+
}
|
|
60963
61242
|
getNoteX(_note, requestedPosition) {
|
|
60964
61243
|
const g = this._glyph;
|
|
60965
61244
|
if (g) {
|
|
@@ -61054,7 +61333,6 @@ class BeamingHelper {
|
|
|
61054
61333
|
voice = null;
|
|
61055
61334
|
beats = [];
|
|
61056
61335
|
shortestDuration = Duration.QuadrupleWhole;
|
|
61057
|
-
tremoloDuration;
|
|
61058
61336
|
/**
|
|
61059
61337
|
* an indicator whether any beat has a tuplet on it.
|
|
61060
61338
|
*/
|
|
@@ -61097,43 +61375,9 @@ class BeamingHelper {
|
|
|
61097
61375
|
this.drawingInfos.clear();
|
|
61098
61376
|
}
|
|
61099
61377
|
}
|
|
61100
|
-
direction = BeamDirection.Up;
|
|
61101
61378
|
finish() {
|
|
61102
|
-
this.direction = this._calculateDirection();
|
|
61103
61379
|
this._renderer.completeBeamingHelper(this);
|
|
61104
61380
|
}
|
|
61105
|
-
_calculateDirection() {
|
|
61106
|
-
// no proper voice (should not happen usually)
|
|
61107
|
-
if (!this.voice) {
|
|
61108
|
-
return BeamDirection.Up;
|
|
61109
|
-
}
|
|
61110
|
-
// we have a preferred direction
|
|
61111
|
-
if (this.preferredBeamDirection !== null) {
|
|
61112
|
-
return this.preferredBeamDirection;
|
|
61113
|
-
}
|
|
61114
|
-
// on multi-voice setups secondary voices are always down
|
|
61115
|
-
if (this.voice.index > 0) {
|
|
61116
|
-
return this._invert(BeamDirection.Down);
|
|
61117
|
-
}
|
|
61118
|
-
// on multi-voice setups primary voices are always up
|
|
61119
|
-
if (this.voice.bar.isMultiVoice) {
|
|
61120
|
-
return this._invert(BeamDirection.Up);
|
|
61121
|
-
}
|
|
61122
|
-
// grace notes are always up
|
|
61123
|
-
if (this.beats[0].graceType !== GraceType.None) {
|
|
61124
|
-
return this._invert(BeamDirection.Up);
|
|
61125
|
-
}
|
|
61126
|
-
// the average line is used for determination
|
|
61127
|
-
// key lowerequal than middle line -> up
|
|
61128
|
-
// key higher than middle line -> down
|
|
61129
|
-
if (this.highestNoteInHelper && this.lowestNoteInHelper) {
|
|
61130
|
-
const highestNotePosition = this._renderer.getNoteY(this.highestNoteInHelper, NoteYPosition.Center);
|
|
61131
|
-
const lowestNotePosition = this._renderer.getNoteY(this.lowestNoteInHelper, NoteYPosition.Center);
|
|
61132
|
-
const avg = (highestNotePosition + lowestNotePosition) / 2;
|
|
61133
|
-
return this._invert(this._renderer.middleYPosition < avg ? BeamDirection.Up : BeamDirection.Down);
|
|
61134
|
-
}
|
|
61135
|
-
return this._invert(BeamDirection.Up);
|
|
61136
|
-
}
|
|
61137
61381
|
static computeLineHeightsForRest(duration) {
|
|
61138
61382
|
switch (duration) {
|
|
61139
61383
|
case Duration.QuadrupleWhole:
|
|
@@ -61161,18 +61405,6 @@ class BeamingHelper {
|
|
|
61161
61405
|
}
|
|
61162
61406
|
return [0, 0];
|
|
61163
61407
|
}
|
|
61164
|
-
_invert(direction) {
|
|
61165
|
-
if (!this.invertBeamDirection) {
|
|
61166
|
-
return direction;
|
|
61167
|
-
}
|
|
61168
|
-
switch (direction) {
|
|
61169
|
-
case BeamDirection.Down:
|
|
61170
|
-
return BeamDirection.Up;
|
|
61171
|
-
// case BeamDirection.Up:
|
|
61172
|
-
default:
|
|
61173
|
-
return BeamDirection.Down;
|
|
61174
|
-
}
|
|
61175
|
-
}
|
|
61176
61408
|
checkBeat(beat) {
|
|
61177
61409
|
if (beat.invertBeamDirection) {
|
|
61178
61410
|
this.invertBeamDirection = true;
|
|
@@ -61206,11 +61438,6 @@ class BeamingHelper {
|
|
|
61206
61438
|
if (beat.hasTuplet) {
|
|
61207
61439
|
this.hasTuplet = true;
|
|
61208
61440
|
}
|
|
61209
|
-
if (beat.isTremolo) {
|
|
61210
|
-
if (!this.tremoloDuration || this.tremoloDuration < beat.tremoloSpeed) {
|
|
61211
|
-
this.tremoloDuration = beat.tremoloSpeed;
|
|
61212
|
-
}
|
|
61213
|
-
}
|
|
61214
61441
|
if (beat.graceType !== GraceType.None) {
|
|
61215
61442
|
this.graceType = beat.graceType;
|
|
61216
61443
|
}
|
|
@@ -62109,9 +62336,6 @@ class BarRendererBase {
|
|
|
62109
62336
|
}
|
|
62110
62337
|
completeBeamingHelper(_helper) {
|
|
62111
62338
|
}
|
|
62112
|
-
getBeatDirection(beat) {
|
|
62113
|
-
return this.helpers.getBeamingHelperForBeat(beat)?.direction ?? BeamDirection.Up;
|
|
62114
|
-
}
|
|
62115
62339
|
}
|
|
62116
62340
|
|
|
62117
62341
|
/**
|
|
@@ -67194,11 +67418,11 @@ class NumberedBeatGlyph extends BeatOnNoteGlyphBase {
|
|
|
67194
67418
|
beatBounds.addNote(noteBounds);
|
|
67195
67419
|
}
|
|
67196
67420
|
}
|
|
67197
|
-
getLowestNoteY() {
|
|
67198
|
-
return this._internalGetNoteY(
|
|
67421
|
+
getLowestNoteY(requestedPosition) {
|
|
67422
|
+
return this._internalGetNoteY(requestedPosition);
|
|
67199
67423
|
}
|
|
67200
|
-
getHighestNoteY() {
|
|
67201
|
-
return this._internalGetNoteY(
|
|
67424
|
+
getHighestNoteY(requestedPosition) {
|
|
67425
|
+
return this._internalGetNoteY(requestedPosition);
|
|
67202
67426
|
}
|
|
67203
67427
|
getNoteY(_note, requestedPosition) {
|
|
67204
67428
|
return this._internalGetNoteY(requestedPosition);
|
|
@@ -67647,6 +67871,12 @@ class NumberedDashBeatContainerGlyph extends BeatContainerGlyphBase {
|
|
|
67647
67871
|
get isLastOfVoice() {
|
|
67648
67872
|
return false;
|
|
67649
67873
|
}
|
|
67874
|
+
getLowestNoteY(_requestedPosition) {
|
|
67875
|
+
return 0;
|
|
67876
|
+
}
|
|
67877
|
+
getHighestNoteY(_requestedPosition) {
|
|
67878
|
+
return 0;
|
|
67879
|
+
}
|
|
67650
67880
|
getNoteY(_note, _requestedPosition) {
|
|
67651
67881
|
return 0;
|
|
67652
67882
|
}
|
|
@@ -67798,6 +68028,11 @@ class FlagGlyph extends MusicFontGlyph {
|
|
|
67798
68028
|
constructor(x, y, duration, direction, isGrace) {
|
|
67799
68029
|
super(x, y, isGrace ? EngravingSettings.GraceScale : 1, FlagGlyph.getSymbol(duration, direction, isGrace));
|
|
67800
68030
|
}
|
|
68031
|
+
paint(cx, cy, canvas) {
|
|
68032
|
+
const c = canvas.color;
|
|
68033
|
+
super.paint(cx, cy, canvas);
|
|
68034
|
+
canvas.color = c;
|
|
68035
|
+
}
|
|
67801
68036
|
static getSymbol(duration, direction, isGrace) {
|
|
67802
68037
|
if (isGrace) {
|
|
67803
68038
|
duration = Duration.Eighth;
|
|
@@ -68002,9 +68237,17 @@ class LineBarRenderer extends BarRendererBase {
|
|
|
68002
68237
|
}
|
|
68003
68238
|
}
|
|
68004
68239
|
}
|
|
68240
|
+
getBeatDirection(beat) {
|
|
68241
|
+
const helper = this.helpers.getBeamingHelperForBeat(beat);
|
|
68242
|
+
return helper ? this.getBeamDirection(helper) : BeamDirection.Up;
|
|
68243
|
+
}
|
|
68005
68244
|
getTupletBeamDirection(helper) {
|
|
68006
68245
|
return this.getBeamDirection(helper);
|
|
68007
68246
|
}
|
|
68247
|
+
calculateBeamYWithDirection(h, x, direction) {
|
|
68248
|
+
this.ensureBeamDrawingInfo(h, direction);
|
|
68249
|
+
return h.drawingInfos.get(direction).calcY(x);
|
|
68250
|
+
}
|
|
68008
68251
|
_paintTupletHelper(cx, cy, canvas, h, beatElement, bracketsAsArcs) {
|
|
68009
68252
|
const res = this.resources;
|
|
68010
68253
|
const oldAlign = canvas.textAlign;
|
|
@@ -68313,26 +68556,6 @@ class LineBarRenderer extends BarRendererBase {
|
|
|
68313
68556
|
}
|
|
68314
68557
|
}
|
|
68315
68558
|
}
|
|
68316
|
-
getFlagStemSize(duration, forceMinStem = false) {
|
|
68317
|
-
let size = 0;
|
|
68318
|
-
switch (duration) {
|
|
68319
|
-
case Duration.QuadrupleWhole:
|
|
68320
|
-
case Duration.Half:
|
|
68321
|
-
case Duration.Quarter:
|
|
68322
|
-
case Duration.Eighth:
|
|
68323
|
-
case Duration.Sixteenth:
|
|
68324
|
-
case Duration.ThirtySecond:
|
|
68325
|
-
case Duration.SixtyFourth:
|
|
68326
|
-
case Duration.OneHundredTwentyEighth:
|
|
68327
|
-
case Duration.TwoHundredFiftySixth:
|
|
68328
|
-
size = this.smuflMetrics.standardStemLength + this.smuflMetrics.stemFlagOffsets.get(duration);
|
|
68329
|
-
break;
|
|
68330
|
-
default:
|
|
68331
|
-
size = forceMinStem ? this.smuflMetrics.standardStemLength : 0;
|
|
68332
|
-
break;
|
|
68333
|
-
}
|
|
68334
|
-
return size;
|
|
68335
|
-
}
|
|
68336
68559
|
recreatePreBeatGlyphs() {
|
|
68337
68560
|
this._startSpacing = false;
|
|
68338
68561
|
super.recreatePreBeatGlyphs();
|
|
@@ -68344,6 +68567,9 @@ class LineBarRenderer extends BarRendererBase {
|
|
|
68344
68567
|
super.createPreBeatGlyphs();
|
|
68345
68568
|
this.addPreBeatGlyph(new BarLineGlyph(false, this.bar.staff.track.score.stylesheet.extendBarLines));
|
|
68346
68569
|
this.createLinePreBeatGlyphs();
|
|
68570
|
+
if (this.index === 0) {
|
|
68571
|
+
this.createStartSpacing();
|
|
68572
|
+
}
|
|
68347
68573
|
this.addPreBeatGlyph(new BarNumberGlyph(0, this.getLineHeight(-0.5), this.bar.index + 1));
|
|
68348
68574
|
}
|
|
68349
68575
|
createPostBeatGlyphs() {
|
|
@@ -68370,7 +68596,13 @@ class LineBarRenderer extends BarRendererBase {
|
|
|
68370
68596
|
continue;
|
|
68371
68597
|
}
|
|
68372
68598
|
const beatLineX = this.getBeatX(beat, BeatXPosition.Stem);
|
|
68373
|
-
|
|
68599
|
+
let y1 = cy + this.y;
|
|
68600
|
+
if (direction === BeamDirection.Up) {
|
|
68601
|
+
y1 += this.getFlagBottomY(beat, direction);
|
|
68602
|
+
}
|
|
68603
|
+
else {
|
|
68604
|
+
y1 += this.getFlagTopY(beat, direction);
|
|
68605
|
+
}
|
|
68374
68606
|
// ensure we are pixel aligned on the end of the stem to avoid anti-aliasing artifacts
|
|
68375
68607
|
// when combining stems and beams on sub-pixel level
|
|
68376
68608
|
const y2 = (cy + this.y + this.calculateBeamY(h, beatLineX)) | 0;
|
|
@@ -68476,21 +68708,22 @@ class LineBarRenderer extends BarRendererBase {
|
|
|
68476
68708
|
calculateBeamingOverflows(rendererTop, rendererBottom) {
|
|
68477
68709
|
let maxNoteY = 0;
|
|
68478
68710
|
let minNoteY = 0;
|
|
68479
|
-
const noteOverflowPadding = this.getLineHeight(0.5);
|
|
68480
68711
|
for (const v of this.helpers.beamHelpers) {
|
|
68481
68712
|
for (const h of v) {
|
|
68482
68713
|
if (!this.shouldPaintBeamingHelper(h)) ;
|
|
68483
68714
|
else if (h.beats.length === 1 && h.beats[0].duration >= Duration.Half) {
|
|
68484
68715
|
const tupletDirection = this.getTupletBeamDirection(h);
|
|
68485
|
-
|
|
68486
|
-
|
|
68487
|
-
|
|
68716
|
+
const direction = this.getBeamDirection(h);
|
|
68717
|
+
const flagOverflow = this.smuflMetrics.stemFlagOffsets.get(h.beats[0].duration);
|
|
68718
|
+
if (direction === BeamDirection.Up) {
|
|
68719
|
+
let topY = this.getFlagTopY(h.beats[0], direction) - flagOverflow;
|
|
68720
|
+
if (h.hasTuplet && tupletDirection === direction) {
|
|
68488
68721
|
topY -= this.tupletSize + this.tupletOffset;
|
|
68489
68722
|
}
|
|
68490
68723
|
if (topY < maxNoteY) {
|
|
68491
68724
|
maxNoteY = topY;
|
|
68492
68725
|
}
|
|
68493
|
-
if (h.hasTuplet && tupletDirection !==
|
|
68726
|
+
if (h.hasTuplet && tupletDirection !== direction) {
|
|
68494
68727
|
let bottomY = this.getFlagBottomY(h.beats[0], tupletDirection);
|
|
68495
68728
|
bottomY += this.tupletSize + this.tupletOffset;
|
|
68496
68729
|
if (bottomY > minNoteY) {
|
|
@@ -68499,14 +68732,14 @@ class LineBarRenderer extends BarRendererBase {
|
|
|
68499
68732
|
}
|
|
68500
68733
|
}
|
|
68501
68734
|
else {
|
|
68502
|
-
let bottomY = this.getFlagBottomY(h.beats[0],
|
|
68503
|
-
if (h.hasTuplet && tupletDirection ===
|
|
68735
|
+
let bottomY = this.getFlagBottomY(h.beats[0], direction) + flagOverflow;
|
|
68736
|
+
if (h.hasTuplet && tupletDirection === direction) {
|
|
68504
68737
|
bottomY += this.tupletSize + this.tupletOffset;
|
|
68505
68738
|
}
|
|
68506
68739
|
if (bottomY > minNoteY) {
|
|
68507
68740
|
minNoteY = bottomY;
|
|
68508
68741
|
}
|
|
68509
|
-
if (h.hasTuplet && tupletDirection !==
|
|
68742
|
+
if (h.hasTuplet && tupletDirection !== direction) {
|
|
68510
68743
|
let topY = this.getFlagTopY(h.beats[0], tupletDirection);
|
|
68511
68744
|
topY -= this.tupletSize + this.tupletOffset;
|
|
68512
68745
|
if (topY < maxNoteY) {
|
|
@@ -68516,19 +68749,20 @@ class LineBarRenderer extends BarRendererBase {
|
|
|
68516
68749
|
}
|
|
68517
68750
|
}
|
|
68518
68751
|
else {
|
|
68519
|
-
this.
|
|
68520
|
-
|
|
68752
|
+
const direction = this.getBeamDirection(h);
|
|
68753
|
+
this.ensureBeamDrawingInfo(h, direction);
|
|
68754
|
+
const drawingInfo = h.drawingInfos.get(direction);
|
|
68521
68755
|
const tupletDirection = this.getTupletBeamDirection(h);
|
|
68522
|
-
if (
|
|
68756
|
+
if (direction === BeamDirection.Up) {
|
|
68523
68757
|
let topY = Math.min(drawingInfo.startY, drawingInfo.endY);
|
|
68524
|
-
if (h.hasTuplet && tupletDirection ===
|
|
68758
|
+
if (h.hasTuplet && tupletDirection === direction) {
|
|
68525
68759
|
topY -= this.tupletSize + this.tupletOffset;
|
|
68526
68760
|
}
|
|
68527
68761
|
if (topY < maxNoteY) {
|
|
68528
68762
|
maxNoteY = topY;
|
|
68529
68763
|
}
|
|
68530
|
-
let bottomY = this.
|
|
68531
|
-
if (h.hasTuplet && tupletDirection !==
|
|
68764
|
+
let bottomY = this.voiceContainer.getLowestNoteY(h.beatOfLowestNote, NoteYPosition.Bottom);
|
|
68765
|
+
if (h.hasTuplet && tupletDirection !== direction) {
|
|
68532
68766
|
bottomY += this.tupletSize + this.tupletOffset;
|
|
68533
68767
|
}
|
|
68534
68768
|
if (bottomY > minNoteY) {
|
|
@@ -68537,14 +68771,14 @@ class LineBarRenderer extends BarRendererBase {
|
|
|
68537
68771
|
}
|
|
68538
68772
|
else {
|
|
68539
68773
|
let bottomY = Math.max(drawingInfo.startY, drawingInfo.endY);
|
|
68540
|
-
if (h.hasTuplet && tupletDirection ===
|
|
68774
|
+
if (h.hasTuplet && tupletDirection === direction) {
|
|
68541
68775
|
bottomY += this.tupletSize + this.tupletOffset;
|
|
68542
68776
|
}
|
|
68543
68777
|
if (bottomY > minNoteY) {
|
|
68544
68778
|
minNoteY = bottomY;
|
|
68545
68779
|
}
|
|
68546
|
-
let topY = this.
|
|
68547
|
-
if (h.hasTuplet && tupletDirection !==
|
|
68780
|
+
let topY = this.voiceContainer.getHighestNoteY(h.beatOfHighestNote, NoteYPosition.Top);
|
|
68781
|
+
if (h.hasTuplet && tupletDirection !== direction) {
|
|
68548
68782
|
topY -= this.tupletSize + this.tupletOffset;
|
|
68549
68783
|
}
|
|
68550
68784
|
if (topY < maxNoteY) {
|
|
@@ -68621,38 +68855,11 @@ class LineBarRenderer extends BarRendererBase {
|
|
|
68621
68855
|
// 3. any middle elements (notes or rests) shift this diagonal line up/down to avoid overlaps
|
|
68622
68856
|
const drawingInfo = this.initializeBeamDrawingInfo(h, direction);
|
|
68623
68857
|
h.drawingInfos.set(direction, drawingInfo);
|
|
68624
|
-
const isRest = h.isRestBeamHelper;
|
|
68625
|
-
const scale = h.graceType !== GraceType.None ? EngravingSettings.GraceScale : 1;
|
|
68626
68858
|
const barCount = ModelUtils.getIndex(h.shortestDuration) - 2;
|
|
68627
68859
|
// 3. adjust beam drawing order
|
|
68628
68860
|
// we can only draw up to 2 beams towards the noteheads, then we have to grow to the other side
|
|
68629
68861
|
// here we shift accordingly
|
|
68630
|
-
|
|
68631
|
-
if (barCount > 2 && !isRest) {
|
|
68632
|
-
const beamSpacing = this.beamSpacing * scale;
|
|
68633
|
-
const beamThickness = this.beamThickness * scale;
|
|
68634
|
-
const totalBarsHeight = barCount * beamThickness + (barCount - 1) * beamSpacing;
|
|
68635
|
-
if (direction === BeamDirection.Up) {
|
|
68636
|
-
const bottomBarY = drawingInfo.startY + 2 * beamThickness + beamSpacing;
|
|
68637
|
-
const barTopY = bottomBarY - totalBarsHeight;
|
|
68638
|
-
const diff = drawingInfo.startY - barTopY;
|
|
68639
|
-
if (diff > 0) {
|
|
68640
|
-
barDrawingShift = diff * -1;
|
|
68641
|
-
drawingInfo.startY -= diff;
|
|
68642
|
-
drawingInfo.endY -= diff;
|
|
68643
|
-
}
|
|
68644
|
-
}
|
|
68645
|
-
else {
|
|
68646
|
-
const topBarY = drawingInfo.startY - 2 * beamThickness + beamSpacing;
|
|
68647
|
-
const barBottomY = topBarY + totalBarsHeight;
|
|
68648
|
-
const diff = barBottomY - drawingInfo.startY;
|
|
68649
|
-
if (diff > 0) {
|
|
68650
|
-
barDrawingShift = diff;
|
|
68651
|
-
drawingInfo.startY += diff;
|
|
68652
|
-
drawingInfo.endY += diff;
|
|
68653
|
-
}
|
|
68654
|
-
}
|
|
68655
|
-
}
|
|
68862
|
+
const barDrawingShift = this.applyBarShift(h, direction, drawingInfo, barCount);
|
|
68656
68863
|
// 4. let middle elements shift up/down
|
|
68657
68864
|
if (h.beats.length > 1) {
|
|
68658
68865
|
// check if highest note shifts bar up or down
|
|
@@ -68708,9 +68915,9 @@ class LineBarRenderer extends BarRendererBase {
|
|
|
68708
68915
|
if (h.slashBeats.length > 0) {
|
|
68709
68916
|
for (const b of h.slashBeats) {
|
|
68710
68917
|
const yGivenByCurrentValues = drawingInfo.calcY(this.getBeatX(b, BeatXPosition.Stem));
|
|
68711
|
-
const yNeededForSlash =
|
|
68712
|
-
? this.getFlagTopY(b,
|
|
68713
|
-
: this.getFlagBottomY(b,
|
|
68918
|
+
const yNeededForSlash = direction === BeamDirection.Up
|
|
68919
|
+
? this.getFlagTopY(b, direction)
|
|
68920
|
+
: this.getFlagBottomY(b, direction);
|
|
68714
68921
|
const diff = yNeededForSlash - yGivenByCurrentValues;
|
|
68715
68922
|
if (diff > 0) {
|
|
68716
68923
|
drawingInfo.startY += diff;
|
|
@@ -68720,6 +68927,37 @@ class LineBarRenderer extends BarRendererBase {
|
|
|
68720
68927
|
}
|
|
68721
68928
|
}
|
|
68722
68929
|
}
|
|
68930
|
+
applyBarShift(h, direction, drawingInfo, barCount) {
|
|
68931
|
+
let barDrawingShift = 0;
|
|
68932
|
+
const isRest = h.isRestBeamHelper;
|
|
68933
|
+
const scale = h.graceType !== GraceType.None ? EngravingSettings.GraceScale : 1;
|
|
68934
|
+
if (barCount > 2 && !isRest) {
|
|
68935
|
+
const beamSpacing = this.beamSpacing * scale;
|
|
68936
|
+
const beamThickness = this.beamThickness * scale;
|
|
68937
|
+
const totalBarsHeight = barCount * beamThickness + (barCount - 1) * beamSpacing;
|
|
68938
|
+
if (direction === BeamDirection.Up) {
|
|
68939
|
+
const bottomBarY = drawingInfo.startY + 2 * beamThickness + beamSpacing;
|
|
68940
|
+
const barTopY = bottomBarY - totalBarsHeight;
|
|
68941
|
+
const diff = drawingInfo.startY - barTopY;
|
|
68942
|
+
if (diff > 0) {
|
|
68943
|
+
barDrawingShift = diff * -1;
|
|
68944
|
+
drawingInfo.startY -= diff;
|
|
68945
|
+
drawingInfo.endY -= diff;
|
|
68946
|
+
}
|
|
68947
|
+
}
|
|
68948
|
+
else {
|
|
68949
|
+
const topBarY = drawingInfo.startY - 2 * beamThickness + beamSpacing;
|
|
68950
|
+
const barBottomY = topBarY + totalBarsHeight;
|
|
68951
|
+
const diff = barBottomY - drawingInfo.startY;
|
|
68952
|
+
if (diff > 0) {
|
|
68953
|
+
barDrawingShift = diff;
|
|
68954
|
+
drawingInfo.startY += diff;
|
|
68955
|
+
drawingInfo.endY += diff;
|
|
68956
|
+
}
|
|
68957
|
+
}
|
|
68958
|
+
}
|
|
68959
|
+
return barDrawingShift;
|
|
68960
|
+
}
|
|
68723
68961
|
getMinLineOfBeat(_beat) {
|
|
68724
68962
|
return 0;
|
|
68725
68963
|
}
|
|
@@ -68823,7 +69061,9 @@ class NumberedBarRenderer extends LineBarRenderer {
|
|
|
68823
69061
|
for (const additionalNumber of container.iterateAdditionalNumbers()) {
|
|
68824
69062
|
barCount = additionalNumber.barCount;
|
|
68825
69063
|
beatLineX =
|
|
68826
|
-
this.beatGlyphsStart +
|
|
69064
|
+
this.beatGlyphsStart +
|
|
69065
|
+
additionalNumber.x +
|
|
69066
|
+
additionalNumber.getBeatX(BeatXPosition.PreNotes, false);
|
|
68827
69067
|
for (let barIndex = 0; barIndex < barCount; barIndex++) {
|
|
68828
69068
|
const barY = barStart + barIndex * barSpacing;
|
|
68829
69069
|
const additionalBarEndX = this.beatGlyphsStart +
|
|
@@ -68888,44 +69128,12 @@ class NumberedBarRenderer extends LineBarRenderer {
|
|
|
68888
69128
|
}
|
|
68889
69129
|
return this.getLineY(0);
|
|
68890
69130
|
}
|
|
68891
|
-
completeBeamingHelper(helper) {
|
|
68892
|
-
super.completeBeamingHelper(helper);
|
|
68893
|
-
helper.direction = BeamDirection.Down;
|
|
68894
|
-
}
|
|
68895
69131
|
getBeamDirection(_helper) {
|
|
68896
69132
|
return BeamDirection.Down;
|
|
68897
69133
|
}
|
|
68898
69134
|
getTupletBeamDirection(_helper) {
|
|
68899
69135
|
return BeamDirection.Up;
|
|
68900
69136
|
}
|
|
68901
|
-
getNoteY(note, requestedPosition) {
|
|
68902
|
-
let y = super.getNoteY(note, requestedPosition);
|
|
68903
|
-
if (Number.isNaN(y)) {
|
|
68904
|
-
y = this.getLineY(0);
|
|
68905
|
-
}
|
|
68906
|
-
return y;
|
|
68907
|
-
}
|
|
68908
|
-
calculateBeamYWithDirection(h, _x, direction) {
|
|
68909
|
-
if (h.beats.length === 0) {
|
|
68910
|
-
return this.getLineY(0);
|
|
68911
|
-
}
|
|
68912
|
-
this.ensureBeamDrawingInfo(h, direction);
|
|
68913
|
-
const info = h.drawingInfos.get(direction);
|
|
68914
|
-
if (direction === BeamDirection.Up) {
|
|
68915
|
-
return Math.min(info.startY, info.endY);
|
|
68916
|
-
}
|
|
68917
|
-
else {
|
|
68918
|
-
return Math.max(info.startY, info.endY);
|
|
68919
|
-
}
|
|
68920
|
-
}
|
|
68921
|
-
getBarLineStart(beat, _direction) {
|
|
68922
|
-
// NOTE: this is only for the overflow calculation, this renderer has a custom bar drawing logic
|
|
68923
|
-
const container = this.voiceContainer.getBeatContainer(beat);
|
|
68924
|
-
if (!container) {
|
|
68925
|
-
return this.voiceContainer.getBoundingBoxTop();
|
|
68926
|
-
}
|
|
68927
|
-
return container.getBoundingBoxTop();
|
|
68928
|
-
}
|
|
68929
69137
|
createPreBeatGlyphs() {
|
|
68930
69138
|
this.wasFirstOfStaff = this.isFirstOfStaff;
|
|
68931
69139
|
if (this.index === 0 || (this.bar.masterBar.isRepeatStart && this._isOnlyNumbered)) {
|
|
@@ -69008,6 +69216,19 @@ class NumberedBarRenderer extends LineBarRenderer {
|
|
|
69008
69216
|
super.paintBeamHelper(cx, cy, canvas, h, flagsElement, beamsElement);
|
|
69009
69217
|
}
|
|
69010
69218
|
}
|
|
69219
|
+
applyBarShift(_h, _direction, _drawingInfo, _barCount) {
|
|
69220
|
+
return 0;
|
|
69221
|
+
}
|
|
69222
|
+
calculateBeamYWithDirection(h, _x, direction) {
|
|
69223
|
+
this.ensureBeamDrawingInfo(h, direction);
|
|
69224
|
+
const info = h.drawingInfos.get(direction);
|
|
69225
|
+
if (direction === BeamDirection.Up) {
|
|
69226
|
+
return Math.min(info.startY, info.endY);
|
|
69227
|
+
}
|
|
69228
|
+
else {
|
|
69229
|
+
return Math.max(info.startY, info.endY);
|
|
69230
|
+
}
|
|
69231
|
+
}
|
|
69011
69232
|
}
|
|
69012
69233
|
|
|
69013
69234
|
/**
|
|
@@ -69176,132 +69397,6 @@ class KeySignatureGlyph extends LeftToRightLayoutingGlyphGroup {
|
|
|
69176
69397
|
}
|
|
69177
69398
|
}
|
|
69178
69399
|
|
|
69179
|
-
/**
|
|
69180
|
-
* @internal
|
|
69181
|
-
*/
|
|
69182
|
-
class NoteHeadGlyphBase extends MusicFontGlyph {
|
|
69183
|
-
centerOnStem = false;
|
|
69184
|
-
constructor(x, y, isGrace, symbol) {
|
|
69185
|
-
super(x, y, isGrace ? EngravingSettings.GraceScale : 1, symbol);
|
|
69186
|
-
}
|
|
69187
|
-
paint(cx, cy, canvas) {
|
|
69188
|
-
if (this.centerOnStem) {
|
|
69189
|
-
this.center = true;
|
|
69190
|
-
}
|
|
69191
|
-
super.paint(cx, cy, canvas);
|
|
69192
|
-
}
|
|
69193
|
-
}
|
|
69194
|
-
/**
|
|
69195
|
-
* @internal
|
|
69196
|
-
*/
|
|
69197
|
-
class NoteHeadGlyph extends NoteHeadGlyphBase {
|
|
69198
|
-
constructor(x, y, duration, isGrace) {
|
|
69199
|
-
super(x, y, isGrace, NoteHeadGlyph.getSymbol(duration));
|
|
69200
|
-
}
|
|
69201
|
-
static getSymbol(duration) {
|
|
69202
|
-
switch (duration) {
|
|
69203
|
-
case Duration.QuadrupleWhole:
|
|
69204
|
-
return MusicFontSymbol.NoteheadDoubleWholeSquare;
|
|
69205
|
-
case Duration.DoubleWhole:
|
|
69206
|
-
return MusicFontSymbol.NoteheadDoubleWhole;
|
|
69207
|
-
case Duration.Whole:
|
|
69208
|
-
return MusicFontSymbol.NoteheadWhole;
|
|
69209
|
-
case Duration.Half:
|
|
69210
|
-
return MusicFontSymbol.NoteheadHalf;
|
|
69211
|
-
default:
|
|
69212
|
-
return MusicFontSymbol.NoteheadBlack;
|
|
69213
|
-
}
|
|
69214
|
-
}
|
|
69215
|
-
}
|
|
69216
|
-
|
|
69217
|
-
/**
|
|
69218
|
-
* @internal
|
|
69219
|
-
*/
|
|
69220
|
-
class SlashNoteHeadGlyph extends NoteHeadGlyphBase {
|
|
69221
|
-
beatEffects = new Map();
|
|
69222
|
-
noteHeadElement = NoteSubElement.SlashNoteHead;
|
|
69223
|
-
effectElement = BeatSubElement.SlashEffects;
|
|
69224
|
-
_symbol;
|
|
69225
|
-
stemX = 0;
|
|
69226
|
-
constructor(x, y, duration, isGrace, beat) {
|
|
69227
|
-
super(x, y, isGrace, SlashNoteHeadGlyph.getSymbol(duration));
|
|
69228
|
-
this._symbol = SlashNoteHeadGlyph.getSymbol(duration);
|
|
69229
|
-
this.beat = beat;
|
|
69230
|
-
}
|
|
69231
|
-
paint(cx, cy, canvas) {
|
|
69232
|
-
const _ = this.beat.notes.length === 0
|
|
69233
|
-
? undefined
|
|
69234
|
-
: ElementStyleHelper.note(canvas, this.noteHeadElement, this.beat.notes[0]);
|
|
69235
|
-
try {
|
|
69236
|
-
super.paint(cx, cy, canvas);
|
|
69237
|
-
this._paintEffects(cx, cy, canvas);
|
|
69238
|
-
}
|
|
69239
|
-
finally {
|
|
69240
|
-
_?.[Symbol.dispose]?.();
|
|
69241
|
-
}
|
|
69242
|
-
}
|
|
69243
|
-
_paintEffects(cx, cy, canvas) {
|
|
69244
|
-
const _ = ElementStyleHelper.beat(canvas, this.effectElement, this.beat);
|
|
69245
|
-
try {
|
|
69246
|
-
for (const g of this.beatEffects.values()) {
|
|
69247
|
-
g.paint(cx + this.x, cy + this.y, canvas);
|
|
69248
|
-
}
|
|
69249
|
-
}
|
|
69250
|
-
finally {
|
|
69251
|
-
_?.[Symbol.dispose]?.();
|
|
69252
|
-
}
|
|
69253
|
-
}
|
|
69254
|
-
doLayout() {
|
|
69255
|
-
super.doLayout();
|
|
69256
|
-
const effectSpacing = this.renderer.smuflMetrics.onNoteEffectPadding;
|
|
69257
|
-
let effectY = this.renderer.smuflMetrics.glyphHeights.get(this._symbol);
|
|
69258
|
-
let minEffectY = Number.NaN;
|
|
69259
|
-
let maxEffectY = Number.NaN;
|
|
69260
|
-
for (const g of this.beatEffects.values()) {
|
|
69261
|
-
g.y += effectY;
|
|
69262
|
-
g.x += this.width / 2;
|
|
69263
|
-
g.renderer = this.renderer;
|
|
69264
|
-
effectY += g.height + effectSpacing;
|
|
69265
|
-
g.doLayout();
|
|
69266
|
-
if (Number.isNaN(minEffectY) || minEffectY > effectY) {
|
|
69267
|
-
minEffectY = effectY;
|
|
69268
|
-
}
|
|
69269
|
-
if (Number.isNaN(maxEffectY) || maxEffectY < effectY) {
|
|
69270
|
-
maxEffectY = effectY;
|
|
69271
|
-
}
|
|
69272
|
-
}
|
|
69273
|
-
if (!Number.isNaN(minEffectY)) {
|
|
69274
|
-
this.renderer.registerBeatEffectOverflows(minEffectY, maxEffectY);
|
|
69275
|
-
}
|
|
69276
|
-
const direction = this.renderer.getBeatDirection(this.beat);
|
|
69277
|
-
const symbol = this._symbol;
|
|
69278
|
-
if (direction === BeamDirection.Up) {
|
|
69279
|
-
const stemInfoUp = this.renderer.smuflMetrics.stemUp.has(symbol)
|
|
69280
|
-
? this.renderer.smuflMetrics.stemUp.get(symbol).x
|
|
69281
|
-
: 0;
|
|
69282
|
-
this.stemX = stemInfoUp;
|
|
69283
|
-
}
|
|
69284
|
-
else {
|
|
69285
|
-
const stemInfoDown = this.renderer.smuflMetrics.stemDown.has(symbol)
|
|
69286
|
-
? this.renderer.smuflMetrics.stemDown.get(symbol).x
|
|
69287
|
-
: 0;
|
|
69288
|
-
this.stemX = stemInfoDown;
|
|
69289
|
-
}
|
|
69290
|
-
}
|
|
69291
|
-
static getSymbol(duration) {
|
|
69292
|
-
switch (duration) {
|
|
69293
|
-
case Duration.QuadrupleWhole:
|
|
69294
|
-
case Duration.DoubleWhole:
|
|
69295
|
-
case Duration.Whole:
|
|
69296
|
-
return MusicFontSymbol.NoteheadSlashWhiteWhole;
|
|
69297
|
-
case Duration.Half:
|
|
69298
|
-
return MusicFontSymbol.NoteheadSlashWhiteHalf;
|
|
69299
|
-
default:
|
|
69300
|
-
return MusicFontSymbol.NoteheadSlashHorizontalEnds;
|
|
69301
|
-
}
|
|
69302
|
-
}
|
|
69303
|
-
}
|
|
69304
|
-
|
|
69305
69400
|
/**
|
|
69306
69401
|
* @internal
|
|
69307
69402
|
*/
|
|
@@ -69351,6 +69446,44 @@ class ArticStaccatoAboveGlyph extends MusicFontGlyph {
|
|
|
69351
69446
|
}
|
|
69352
69447
|
}
|
|
69353
69448
|
|
|
69449
|
+
/**
|
|
69450
|
+
* @internal
|
|
69451
|
+
*/
|
|
69452
|
+
class NoteHeadGlyphBase extends MusicFontGlyph {
|
|
69453
|
+
centerOnStem = false;
|
|
69454
|
+
constructor(x, y, isGrace, symbol) {
|
|
69455
|
+
super(x, y, isGrace ? EngravingSettings.GraceScale : 1, symbol);
|
|
69456
|
+
}
|
|
69457
|
+
paint(cx, cy, canvas) {
|
|
69458
|
+
if (this.centerOnStem) {
|
|
69459
|
+
this.center = true;
|
|
69460
|
+
}
|
|
69461
|
+
super.paint(cx, cy, canvas);
|
|
69462
|
+
}
|
|
69463
|
+
}
|
|
69464
|
+
/**
|
|
69465
|
+
* @internal
|
|
69466
|
+
*/
|
|
69467
|
+
class NoteHeadGlyph extends NoteHeadGlyphBase {
|
|
69468
|
+
constructor(x, y, duration, isGrace) {
|
|
69469
|
+
super(x, y, isGrace, NoteHeadGlyph.getSymbol(duration));
|
|
69470
|
+
}
|
|
69471
|
+
static getSymbol(duration) {
|
|
69472
|
+
switch (duration) {
|
|
69473
|
+
case Duration.QuadrupleWhole:
|
|
69474
|
+
return MusicFontSymbol.NoteheadDoubleWholeSquare;
|
|
69475
|
+
case Duration.DoubleWhole:
|
|
69476
|
+
return MusicFontSymbol.NoteheadDoubleWhole;
|
|
69477
|
+
case Duration.Whole:
|
|
69478
|
+
return MusicFontSymbol.NoteheadWhole;
|
|
69479
|
+
case Duration.Half:
|
|
69480
|
+
return MusicFontSymbol.NoteheadHalf;
|
|
69481
|
+
default:
|
|
69482
|
+
return MusicFontSymbol.NoteheadBlack;
|
|
69483
|
+
}
|
|
69484
|
+
}
|
|
69485
|
+
}
|
|
69486
|
+
|
|
69354
69487
|
/**
|
|
69355
69488
|
* @internal
|
|
69356
69489
|
*/
|
|
@@ -69714,8 +69847,8 @@ class ScoreNoteChordGlyphBase extends Glyph {
|
|
|
69714
69847
|
_infos = [];
|
|
69715
69848
|
_noteHeadInfo;
|
|
69716
69849
|
noteGroup;
|
|
69717
|
-
|
|
69718
|
-
|
|
69850
|
+
minStepsNote = null;
|
|
69851
|
+
maxStepsNote = null;
|
|
69719
69852
|
get stemX() {
|
|
69720
69853
|
if (!this.noteGroup) {
|
|
69721
69854
|
return 0;
|
|
@@ -69728,25 +69861,19 @@ class ScoreNoteChordGlyphBase extends Glyph {
|
|
|
69728
69861
|
super(0, 0);
|
|
69729
69862
|
}
|
|
69730
69863
|
getBoundingBoxTop() {
|
|
69731
|
-
return this.
|
|
69864
|
+
return this.minStepsNote ? this.minStepsNote.glyph.getBoundingBoxTop() : this.y;
|
|
69732
69865
|
}
|
|
69733
69866
|
getBoundingBoxBottom() {
|
|
69734
|
-
return this.
|
|
69735
|
-
}
|
|
69736
|
-
getLowestNoteY() {
|
|
69737
|
-
return this.maxNote ? this.renderer.getScoreY(this.maxNote.steps) : 0;
|
|
69738
|
-
}
|
|
69739
|
-
getHighestNoteY() {
|
|
69740
|
-
return this.minNote ? this.renderer.getScoreY(this.minNote.steps) : 0;
|
|
69867
|
+
return this.maxStepsNote ? this.maxStepsNote.glyph.getBoundingBoxBottom() : this.y + this.height;
|
|
69741
69868
|
}
|
|
69742
69869
|
add(noteGlyph, noteSteps) {
|
|
69743
69870
|
const info = { glyph: noteGlyph, steps: noteSteps };
|
|
69744
69871
|
this._infos.push(info);
|
|
69745
|
-
if (!this.
|
|
69746
|
-
this.
|
|
69872
|
+
if (!this.minStepsNote || this.minStepsNote.steps > info.steps) {
|
|
69873
|
+
this.minStepsNote = info;
|
|
69747
69874
|
}
|
|
69748
|
-
if (!this.
|
|
69749
|
-
this.
|
|
69875
|
+
if (!this.maxStepsNote || this.maxStepsNote.steps < info.steps) {
|
|
69876
|
+
this.maxStepsNote = info;
|
|
69750
69877
|
}
|
|
69751
69878
|
}
|
|
69752
69879
|
_prepareForLayout(info) {
|
|
@@ -69982,7 +70109,7 @@ class ScoreNoteChordGlyphBase extends Glyph {
|
|
|
69982
70109
|
}
|
|
69983
70110
|
}
|
|
69984
70111
|
_paintLedgerLines(cx, cy, canvas) {
|
|
69985
|
-
if (!this.
|
|
70112
|
+
if (!this.minStepsNote) {
|
|
69986
70113
|
return;
|
|
69987
70114
|
}
|
|
69988
70115
|
const scoreRenderer = this.renderer;
|
|
@@ -69994,8 +70121,8 @@ class ScoreNoteChordGlyphBase extends Glyph {
|
|
|
69994
70121
|
const lineSpacing = scoreRenderer.getLineHeight(1);
|
|
69995
70122
|
const firstTopLedgerY = scoreRenderer.getLineY(-1);
|
|
69996
70123
|
const firstBottomLedgerY = scoreRenderer.getLineY(scoreRenderer.drawnLineCount);
|
|
69997
|
-
const minNoteLineY = scoreRenderer.getLineY(this.
|
|
69998
|
-
const maxNoteLineY = scoreRenderer.getLineY(this.
|
|
70124
|
+
const minNoteLineY = scoreRenderer.getLineY(this.minStepsNote.steps / 2);
|
|
70125
|
+
const maxNoteLineY = scoreRenderer.getLineY(this.maxStepsNote.steps / 2);
|
|
69999
70126
|
const lineYOffset = (this.renderer.smuflMetrics.legerLineThickness * scale) / 2;
|
|
70000
70127
|
let y = firstTopLedgerY;
|
|
70001
70128
|
while (y >= minNoteLineY) {
|
|
@@ -70018,21 +70145,87 @@ class ScoreNoteChordGlyphBase extends Glyph {
|
|
|
70018
70145
|
* @internal
|
|
70019
70146
|
*/
|
|
70020
70147
|
class TremoloPickingGlyph extends MusicFontGlyph {
|
|
70021
|
-
constructor(x, y,
|
|
70022
|
-
super(x, y, 1, TremoloPickingGlyph._getSymbol(
|
|
70148
|
+
constructor(x, y, effect) {
|
|
70149
|
+
super(x, y, 1, TremoloPickingGlyph._getSymbol(effect));
|
|
70023
70150
|
}
|
|
70024
|
-
static _getSymbol(
|
|
70025
|
-
|
|
70026
|
-
|
|
70027
|
-
|
|
70028
|
-
|
|
70029
|
-
|
|
70030
|
-
|
|
70031
|
-
|
|
70032
|
-
|
|
70033
|
-
|
|
70151
|
+
static _getSymbol(effect) {
|
|
70152
|
+
if (effect.style === TremoloPickingStyle.BuzzRoll) {
|
|
70153
|
+
return MusicFontSymbol.BuzzRoll;
|
|
70154
|
+
}
|
|
70155
|
+
else {
|
|
70156
|
+
switch (effect.marks) {
|
|
70157
|
+
case 1:
|
|
70158
|
+
return MusicFontSymbol.Tremolo1;
|
|
70159
|
+
case 2:
|
|
70160
|
+
return MusicFontSymbol.Tremolo2;
|
|
70161
|
+
case 3:
|
|
70162
|
+
return MusicFontSymbol.Tremolo3;
|
|
70163
|
+
case 4:
|
|
70164
|
+
return MusicFontSymbol.Tremolo4;
|
|
70165
|
+
case 5:
|
|
70166
|
+
return MusicFontSymbol.Tremolo5;
|
|
70167
|
+
default:
|
|
70168
|
+
return MusicFontSymbol.None;
|
|
70169
|
+
}
|
|
70034
70170
|
}
|
|
70035
70171
|
}
|
|
70172
|
+
stemExtensionHeight = 0;
|
|
70173
|
+
alignTremoloPickingGlyph(direction, flagEnd, firstNoteY, duration) {
|
|
70174
|
+
const lr = this.renderer;
|
|
70175
|
+
const smufl = lr.smuflMetrics;
|
|
70176
|
+
let tremoloY = 0;
|
|
70177
|
+
const tremoloOverlap = smufl.glyphHeights.get(MusicFontSymbol.Tremolo1) / 2;
|
|
70178
|
+
const tremoloCenterOffset = this.height / 2;
|
|
70179
|
+
// whether the center or top bar should be aligned with a staff line
|
|
70180
|
+
const forceAlignWithStaffLine = this.symbol === MusicFontSymbol.Tremolo1;
|
|
70181
|
+
const lineSpacing = lr.lineSpacing;
|
|
70182
|
+
const spacing = forceAlignWithStaffLine ? lineSpacing : lineSpacing / 2;
|
|
70183
|
+
if (direction === BeamDirection.Up) {
|
|
70184
|
+
// start at note
|
|
70185
|
+
let flagBottom = flagEnd;
|
|
70186
|
+
// to bottom of stem
|
|
70187
|
+
flagBottom += smufl.stemFlagHeight.get(duration);
|
|
70188
|
+
flagBottom -= smufl.stemFlagOffsets.get(duration);
|
|
70189
|
+
// align with closest step line
|
|
70190
|
+
tremoloY = spacing * Math.ceil(flagBottom / spacing);
|
|
70191
|
+
// ensure at least 1 staff space distance between note and tremolo bottom bar
|
|
70192
|
+
const tremoloBottomY = tremoloY + tremoloCenterOffset;
|
|
70193
|
+
const minSpacingY = firstNoteY - lineSpacing;
|
|
70194
|
+
if (minSpacingY < tremoloBottomY) {
|
|
70195
|
+
tremoloY = minSpacingY - tremoloCenterOffset;
|
|
70196
|
+
}
|
|
70197
|
+
// reserve the additional space needed in the stem height
|
|
70198
|
+
flagBottom += tremoloOverlap;
|
|
70199
|
+
const tremoloTop = tremoloY - tremoloCenterOffset;
|
|
70200
|
+
if (flagBottom > tremoloTop) {
|
|
70201
|
+
this.stemExtensionHeight = flagBottom - tremoloTop;
|
|
70202
|
+
}
|
|
70203
|
+
else {
|
|
70204
|
+
this.stemExtensionHeight = 0;
|
|
70205
|
+
}
|
|
70206
|
+
}
|
|
70207
|
+
else {
|
|
70208
|
+
// same logic as above but inverted
|
|
70209
|
+
let flagTop = flagEnd;
|
|
70210
|
+
flagTop -= smufl.stemFlagHeight.get(duration);
|
|
70211
|
+
flagTop += smufl.stemFlagOffsets.get(duration);
|
|
70212
|
+
tremoloY = spacing * Math.floor(flagTop / spacing);
|
|
70213
|
+
const tremoloTopY = tremoloY - tremoloCenterOffset;
|
|
70214
|
+
const minSpacingY = firstNoteY + lineSpacing;
|
|
70215
|
+
if (minSpacingY > tremoloTopY) {
|
|
70216
|
+
tremoloY = minSpacingY + tremoloCenterOffset;
|
|
70217
|
+
}
|
|
70218
|
+
flagTop -= tremoloOverlap;
|
|
70219
|
+
const tremoloBottom = tremoloY + tremoloCenterOffset;
|
|
70220
|
+
if (flagTop < tremoloBottom) {
|
|
70221
|
+
this.stemExtensionHeight = tremoloBottom - flagTop;
|
|
70222
|
+
}
|
|
70223
|
+
else {
|
|
70224
|
+
this.stemExtensionHeight = 0;
|
|
70225
|
+
}
|
|
70226
|
+
}
|
|
70227
|
+
this.y = tremoloY;
|
|
70228
|
+
}
|
|
70036
70229
|
}
|
|
70037
70230
|
|
|
70038
70231
|
/**
|
|
@@ -70043,6 +70236,7 @@ class ScoreNoteChordGlyph extends ScoreNoteChordGlyphBase {
|
|
|
70043
70236
|
_notes = [];
|
|
70044
70237
|
_deadSlapped = null;
|
|
70045
70238
|
_tremoloPicking = null;
|
|
70239
|
+
_stemLengthExtension = 0;
|
|
70046
70240
|
aboveBeatEffects = new Map();
|
|
70047
70241
|
belowBeatEffects = new Map();
|
|
70048
70242
|
beat;
|
|
@@ -70064,7 +70258,7 @@ class ScoreNoteChordGlyph extends ScoreNoteChordGlyphBase {
|
|
|
70064
70258
|
return new ScoreChordNoteHeadInfo(this.direction);
|
|
70065
70259
|
}
|
|
70066
70260
|
const staff = this.beat.voice.bar.staff;
|
|
70067
|
-
const key = `score.noteheads.${staff.track.index}.${staff.index}.${this.beat.absoluteDisplayStart}`;
|
|
70261
|
+
const key = `score.noteheads.${staff.track.index}.${staff.index}.${this.beat.voice.bar.index}.${this.beat.absoluteDisplayStart}`;
|
|
70068
70262
|
let existing = this.renderer.staff.getSharedLayoutData(key, undefined);
|
|
70069
70263
|
if (!existing) {
|
|
70070
70264
|
existing = new ScoreChordNoteHeadInfo(this.direction);
|
|
@@ -70097,19 +70291,26 @@ class ScoreNoteChordGlyph extends ScoreNoteChordGlyphBase {
|
|
|
70097
70291
|
}
|
|
70098
70292
|
return 0;
|
|
70099
70293
|
}
|
|
70294
|
+
getLowestNoteY(requestedPosition) {
|
|
70295
|
+
return this.maxStepsNote ? this._internalGetNoteY(this.maxStepsNote.glyph, requestedPosition) : 0;
|
|
70296
|
+
}
|
|
70297
|
+
getHighestNoteY(requestedPosition) {
|
|
70298
|
+
return this.minStepsNote ? this._internalGetNoteY(this.minStepsNote.glyph, requestedPosition) : 0;
|
|
70299
|
+
}
|
|
70100
70300
|
_internalGetNoteY(n, requestedPosition) {
|
|
70101
70301
|
let pos = this.y + n.y;
|
|
70302
|
+
const sr = this.renderer;
|
|
70102
70303
|
const scale = this.beat.graceType !== GraceType.None ? EngravingSettings.GraceScale : 1;
|
|
70103
70304
|
switch (requestedPosition) {
|
|
70104
70305
|
case NoteYPosition.TopWithStem:
|
|
70105
70306
|
// stem start
|
|
70106
70307
|
pos -=
|
|
70107
|
-
(
|
|
70108
|
-
? this.renderer.smuflMetrics.stemUp.get(n.symbol).bottomY
|
|
70109
|
-
: 0) * scale;
|
|
70308
|
+
(sr.smuflMetrics.stemUp.has(n.symbol) ? sr.smuflMetrics.stemUp.get(n.symbol).bottomY : 0) * scale;
|
|
70110
70309
|
// stem size according to duration
|
|
70111
|
-
pos -= this.
|
|
70112
|
-
|
|
70310
|
+
pos -= sr.smuflMetrics.getStemLength(this.beat.duration, sr.hasFlag(this.beat)) * scale;
|
|
70311
|
+
pos -= this._stemLengthExtension;
|
|
70312
|
+
let topCenterY = sr.centerStaffStemY(this.direction);
|
|
70313
|
+
topCenterY -= this._stemLengthExtension;
|
|
70113
70314
|
return Math.min(topCenterY, pos);
|
|
70114
70315
|
case NoteYPosition.Top:
|
|
70115
70316
|
pos -= n.height / 2;
|
|
@@ -70125,20 +70326,20 @@ class ScoreNoteChordGlyph extends ScoreNoteChordGlyphBase {
|
|
|
70125
70326
|
? this.renderer.smuflMetrics.stemDown.get(n.symbol).topY
|
|
70126
70327
|
: -this.renderer.smuflMetrics.glyphHeights.get(n.symbol) / 2) * scale;
|
|
70127
70328
|
// stem size according to duration
|
|
70128
|
-
pos += this.
|
|
70129
|
-
|
|
70329
|
+
pos += sr.smuflMetrics.getStemLength(this.beat.duration, sr.hasFlag(this.beat)) * scale;
|
|
70330
|
+
pos += this._stemLengthExtension;
|
|
70331
|
+
let bottomCenterY = sr.centerStaffStemY(this.direction);
|
|
70332
|
+
bottomCenterY += this._stemLengthExtension;
|
|
70130
70333
|
return Math.max(bottomCenterY, pos);
|
|
70131
70334
|
case NoteYPosition.StemUp:
|
|
70132
70335
|
pos -=
|
|
70133
|
-
(
|
|
70134
|
-
? this.renderer.smuflMetrics.stemUp.get(n.symbol).bottomY
|
|
70135
|
-
: 0) * scale;
|
|
70336
|
+
(sr.smuflMetrics.stemUp.has(n.symbol) ? sr.smuflMetrics.stemUp.get(n.symbol).bottomY : 0) * scale;
|
|
70136
70337
|
break;
|
|
70137
70338
|
case NoteYPosition.StemDown:
|
|
70138
70339
|
pos -=
|
|
70139
|
-
(
|
|
70140
|
-
?
|
|
70141
|
-
: -
|
|
70340
|
+
(sr.smuflMetrics.stemDown.has(n.symbol)
|
|
70341
|
+
? sr.smuflMetrics.stemDown.get(n.symbol).topY
|
|
70342
|
+
: -sr.smuflMetrics.glyphHeights.get(n.symbol) / 2) * scale;
|
|
70142
70343
|
break;
|
|
70143
70344
|
}
|
|
70144
70345
|
return pos;
|
|
@@ -70170,14 +70371,15 @@ class ScoreNoteChordGlyph extends ScoreNoteChordGlyphBase {
|
|
|
70170
70371
|
}
|
|
70171
70372
|
else {
|
|
70172
70373
|
if (this.direction === BeamDirection.Up) {
|
|
70173
|
-
belowBeatEffectsY =
|
|
70374
|
+
belowBeatEffectsY =
|
|
70375
|
+
this._internalGetNoteY(this.maxStepsNote.glyph, NoteYPosition.Bottom) + effectSpacing;
|
|
70174
70376
|
aboveBeatEffectsY =
|
|
70175
|
-
this._internalGetNoteY(this.
|
|
70377
|
+
this._internalGetNoteY(this.minStepsNote.glyph, NoteYPosition.TopWithStem) - effectSpacing;
|
|
70176
70378
|
}
|
|
70177
70379
|
else {
|
|
70178
70380
|
belowBeatEffectsY =
|
|
70179
|
-
this._internalGetNoteY(this.
|
|
70180
|
-
aboveBeatEffectsY = this._internalGetNoteY(this.
|
|
70381
|
+
this._internalGetNoteY(this.maxStepsNote.glyph, NoteYPosition.BottomWithStem) + effectSpacing;
|
|
70382
|
+
aboveBeatEffectsY = this._internalGetNoteY(this.minStepsNote.glyph, NoteYPosition.Top) - effectSpacing;
|
|
70181
70383
|
}
|
|
70182
70384
|
}
|
|
70183
70385
|
let minEffectY = null;
|
|
@@ -70211,27 +70413,27 @@ class ScoreNoteChordGlyph extends ScoreNoteChordGlyphBase {
|
|
|
70211
70413
|
scoreRenderer.registerBeatEffectOverflows(minEffectY, maxEffectY ?? 0);
|
|
70212
70414
|
}
|
|
70213
70415
|
if (this.beat.isTremolo && !this.beat.deadSlapped) {
|
|
70214
|
-
|
|
70215
|
-
let tremoloY = 0;
|
|
70216
|
-
if (direction === BeamDirection.Up) {
|
|
70217
|
-
const topY = this._internalGetNoteY(this.minNote.glyph, NoteYPosition.TopWithStem);
|
|
70218
|
-
const bottomY = this._internalGetNoteY(this.minNote.glyph, NoteYPosition.StemUp);
|
|
70219
|
-
tremoloY = (topY + bottomY) / 2;
|
|
70220
|
-
}
|
|
70221
|
-
else {
|
|
70222
|
-
const topY = this._internalGetNoteY(this.maxNote.glyph, NoteYPosition.StemDown);
|
|
70223
|
-
const bottomY = this._internalGetNoteY(this.maxNote.glyph, NoteYPosition.BottomWithStem);
|
|
70224
|
-
tremoloY = (topY + bottomY) / 2;
|
|
70225
|
-
}
|
|
70226
|
-
let tremoloX = this.stemX;
|
|
70227
|
-
const speed = this.beat.tremoloSpeed;
|
|
70228
|
-
if (this.beat.duration < Duration.Half) {
|
|
70229
|
-
tremoloX = this.width / 2;
|
|
70230
|
-
}
|
|
70231
|
-
this._tremoloPicking = new TremoloPickingGlyph(tremoloX, tremoloY, speed);
|
|
70416
|
+
this._tremoloPicking = new TremoloPickingGlyph(0, 0, this.beat.tremoloPicking);
|
|
70232
70417
|
this._tremoloPicking.renderer = this.renderer;
|
|
70233
70418
|
this._tremoloPicking.doLayout();
|
|
70419
|
+
this._alignTremoloPickingGlyph();
|
|
70420
|
+
}
|
|
70421
|
+
}
|
|
70422
|
+
_alignTremoloPickingGlyph() {
|
|
70423
|
+
const g = this._tremoloPicking;
|
|
70424
|
+
const direction = this.direction;
|
|
70425
|
+
if (direction === BeamDirection.Up) {
|
|
70426
|
+
g.alignTremoloPickingGlyph(direction, this.getHighestNoteY(NoteYPosition.TopWithStem), this.getHighestNoteY(NoteYPosition.Center), this.beat.duration);
|
|
70427
|
+
}
|
|
70428
|
+
else {
|
|
70429
|
+
g.alignTremoloPickingGlyph(direction, this.getLowestNoteY(NoteYPosition.BottomWithStem), this.getLowestNoteY(NoteYPosition.Center), this.beat.duration);
|
|
70430
|
+
}
|
|
70431
|
+
this._stemLengthExtension = g.stemExtensionHeight;
|
|
70432
|
+
let tremoloX = this.stemX;
|
|
70433
|
+
if (this.beat.duration < Duration.Half) {
|
|
70434
|
+
tremoloX = this.width / 2;
|
|
70234
70435
|
}
|
|
70436
|
+
g.x = tremoloX;
|
|
70235
70437
|
}
|
|
70236
70438
|
buildBoundingsLookup(beatBounds, cx, cy) {
|
|
70237
70439
|
for (const note of this._notes) {
|
|
@@ -70480,17 +70682,17 @@ class ScoreWhammyBarGlyph extends ScoreHelperNotesBaseGlyph {
|
|
|
70480
70682
|
if (!endGlyph) {
|
|
70481
70683
|
return false;
|
|
70482
70684
|
}
|
|
70483
|
-
return !!endGlyph.
|
|
70685
|
+
return !!endGlyph.minStepsNote && !!endGlyph.maxStepsNote;
|
|
70484
70686
|
}
|
|
70485
70687
|
getBoundingBoxTop() {
|
|
70486
|
-
if (this._endGlyph?.
|
|
70487
|
-
return this._endGlyph.
|
|
70688
|
+
if (this._endGlyph?.minStepsNote) {
|
|
70689
|
+
return this._endGlyph.minStepsNote.glyph.getBoundingBoxTop();
|
|
70488
70690
|
}
|
|
70489
70691
|
return super.getBoundingBoxTop();
|
|
70490
70692
|
}
|
|
70491
70693
|
getBoundingBoxBottom() {
|
|
70492
|
-
if (this._endGlyph?.
|
|
70493
|
-
return this._endGlyph.
|
|
70694
|
+
if (this._endGlyph?.maxStepsNote) {
|
|
70695
|
+
return this._endGlyph.maxStepsNote.glyph.getBoundingBoxBottom();
|
|
70494
70696
|
}
|
|
70495
70697
|
return super.getBoundingBoxBottom();
|
|
70496
70698
|
}
|
|
@@ -70723,6 +70925,89 @@ class ScoreWhammyBarGlyph extends ScoreHelperNotesBaseGlyph {
|
|
|
70723
70925
|
}
|
|
70724
70926
|
}
|
|
70725
70927
|
|
|
70928
|
+
/**
|
|
70929
|
+
* @internal
|
|
70930
|
+
*/
|
|
70931
|
+
class SlashNoteHeadGlyph extends NoteHeadGlyphBase {
|
|
70932
|
+
beatEffects = new Map();
|
|
70933
|
+
noteHeadElement = NoteSubElement.SlashNoteHead;
|
|
70934
|
+
effectElement = BeatSubElement.SlashEffects;
|
|
70935
|
+
stemX = 0;
|
|
70936
|
+
constructor(x, y, beat) {
|
|
70937
|
+
super(x, y, beat.graceType !== GraceType.None, SlashNoteHeadGlyph.getSymbol(beat.duration));
|
|
70938
|
+
this.beat = beat;
|
|
70939
|
+
}
|
|
70940
|
+
paint(cx, cy, canvas) {
|
|
70941
|
+
const _ = this.beat.notes.length === 0
|
|
70942
|
+
? undefined
|
|
70943
|
+
: ElementStyleHelper.note(canvas, this.noteHeadElement, this.beat.notes[0]);
|
|
70944
|
+
try {
|
|
70945
|
+
super.paint(cx, cy, canvas);
|
|
70946
|
+
this._paintEffects(cx, cy, canvas);
|
|
70947
|
+
}
|
|
70948
|
+
finally {
|
|
70949
|
+
_?.[Symbol.dispose]?.();
|
|
70950
|
+
}
|
|
70951
|
+
}
|
|
70952
|
+
_paintEffects(cx, cy, canvas) {
|
|
70953
|
+
const _ = ElementStyleHelper.beat(canvas, this.effectElement, this.beat);
|
|
70954
|
+
try {
|
|
70955
|
+
for (const g of this.beatEffects.values()) {
|
|
70956
|
+
g.paint(cx + this.x, cy + this.y, canvas);
|
|
70957
|
+
}
|
|
70958
|
+
}
|
|
70959
|
+
finally {
|
|
70960
|
+
_?.[Symbol.dispose]?.();
|
|
70961
|
+
}
|
|
70962
|
+
}
|
|
70963
|
+
doLayout() {
|
|
70964
|
+
super.doLayout();
|
|
70965
|
+
const lr = this.renderer;
|
|
70966
|
+
const effectSpacing = lr.smuflMetrics.onNoteEffectPadding;
|
|
70967
|
+
let effectY = lr.smuflMetrics.glyphHeights.get(this.symbol);
|
|
70968
|
+
let minEffectY = Number.NaN;
|
|
70969
|
+
let maxEffectY = Number.NaN;
|
|
70970
|
+
for (const g of this.beatEffects.values()) {
|
|
70971
|
+
g.y += effectY;
|
|
70972
|
+
g.x += this.width / 2;
|
|
70973
|
+
g.renderer = lr;
|
|
70974
|
+
effectY += g.height + effectSpacing;
|
|
70975
|
+
g.doLayout();
|
|
70976
|
+
if (Number.isNaN(minEffectY) || minEffectY > effectY) {
|
|
70977
|
+
minEffectY = effectY;
|
|
70978
|
+
}
|
|
70979
|
+
if (Number.isNaN(maxEffectY) || maxEffectY < effectY) {
|
|
70980
|
+
maxEffectY = effectY;
|
|
70981
|
+
}
|
|
70982
|
+
}
|
|
70983
|
+
if (!Number.isNaN(minEffectY)) {
|
|
70984
|
+
lr.registerBeatEffectOverflows(minEffectY, maxEffectY);
|
|
70985
|
+
}
|
|
70986
|
+
const direction = lr.getBeatDirection(this.beat);
|
|
70987
|
+
const symbol = this.symbol;
|
|
70988
|
+
if (direction === BeamDirection.Up) {
|
|
70989
|
+
const stemInfoUp = lr.smuflMetrics.stemUp.has(symbol) ? lr.smuflMetrics.stemUp.get(symbol).x : 0;
|
|
70990
|
+
this.stemX = stemInfoUp;
|
|
70991
|
+
}
|
|
70992
|
+
else {
|
|
70993
|
+
const stemInfoDown = lr.smuflMetrics.stemDown.has(symbol) ? lr.smuflMetrics.stemDown.get(symbol).x : 0;
|
|
70994
|
+
this.stemX = stemInfoDown;
|
|
70995
|
+
}
|
|
70996
|
+
}
|
|
70997
|
+
static getSymbol(duration) {
|
|
70998
|
+
switch (duration) {
|
|
70999
|
+
case Duration.QuadrupleWhole:
|
|
71000
|
+
case Duration.DoubleWhole:
|
|
71001
|
+
case Duration.Whole:
|
|
71002
|
+
return MusicFontSymbol.NoteheadSlashWhiteWhole;
|
|
71003
|
+
case Duration.Half:
|
|
71004
|
+
return MusicFontSymbol.NoteheadSlashWhiteHalf;
|
|
71005
|
+
default:
|
|
71006
|
+
return MusicFontSymbol.NoteheadSlashHorizontalEnds;
|
|
71007
|
+
}
|
|
71008
|
+
}
|
|
71009
|
+
}
|
|
71010
|
+
|
|
70726
71011
|
/**
|
|
70727
71012
|
* @internal
|
|
70728
71013
|
*/
|
|
@@ -70761,9 +71046,6 @@ class ScoreBeatGlyph extends BeatOnNoteGlyphBase {
|
|
|
70761
71046
|
get effectElement() {
|
|
70762
71047
|
return BeatSubElement.StandardNotationEffects;
|
|
70763
71048
|
}
|
|
70764
|
-
getNoteX(note, requestedPosition) {
|
|
70765
|
-
return this.noteHeads ? this.noteHeads.getNoteX(note, requestedPosition) : 0;
|
|
70766
|
-
}
|
|
70767
71049
|
buildBoundingsLookup(beatBounds, cx, cy) {
|
|
70768
71050
|
if (this.noteHeads) {
|
|
70769
71051
|
this.noteHeads.buildBoundingsLookup(beatBounds, cx + this.x, cy + this.y);
|
|
@@ -70795,20 +71077,34 @@ class ScoreBeatGlyph extends BeatOnNoteGlyphBase {
|
|
|
70795
71077
|
}
|
|
70796
71078
|
return y;
|
|
70797
71079
|
}
|
|
70798
|
-
getLowestNoteY() {
|
|
70799
|
-
|
|
71080
|
+
getLowestNoteY(requestedPosition) {
|
|
71081
|
+
// NOTE: slash handled automatically
|
|
71082
|
+
return this.noteHeads ? this.noteHeads.getLowestNoteY(requestedPosition) : 0;
|
|
70800
71083
|
}
|
|
70801
|
-
getHighestNoteY() {
|
|
70802
|
-
|
|
71084
|
+
getHighestNoteY(requestedPosition) {
|
|
71085
|
+
// NOTE: slash handled automatically
|
|
71086
|
+
return this.noteHeads ? this.noteHeads.getHighestNoteY(requestedPosition) : 0;
|
|
70803
71087
|
}
|
|
70804
71088
|
getNoteY(note, requestedPosition) {
|
|
71089
|
+
// for slashed beats always lookup first note
|
|
71090
|
+
if (note.beat.slashed) {
|
|
71091
|
+
note = note.beat.notes[0];
|
|
71092
|
+
}
|
|
70805
71093
|
return this.noteHeads ? this.noteHeads.getNoteY(note, requestedPosition) : 0;
|
|
70806
71094
|
}
|
|
71095
|
+
getNoteX(note, requestedPosition) {
|
|
71096
|
+
// for slashed beats always lookup first note
|
|
71097
|
+
if (note.beat.slashed) {
|
|
71098
|
+
note = note.beat.notes[0];
|
|
71099
|
+
}
|
|
71100
|
+
return this.noteHeads ? this.noteHeads.getNoteX(note, requestedPosition) : 0;
|
|
71101
|
+
}
|
|
70807
71102
|
getRestY(requestedPosition) {
|
|
70808
71103
|
const g = this.restGlyph;
|
|
70809
71104
|
if (g) {
|
|
70810
71105
|
switch (requestedPosition) {
|
|
70811
71106
|
case NoteYPosition.TopWithStem:
|
|
71107
|
+
return g.getBoundingBoxTop() - this.renderer.smuflMetrics.getStemLength(Duration.Quarter, true);
|
|
70812
71108
|
case NoteYPosition.Top:
|
|
70813
71109
|
return g.getBoundingBoxTop();
|
|
70814
71110
|
case NoteYPosition.Center:
|
|
@@ -70816,8 +71112,9 @@ class ScoreBeatGlyph extends BeatOnNoteGlyphBase {
|
|
|
70816
71112
|
case NoteYPosition.StemDown:
|
|
70817
71113
|
return g.getBoundingBoxTop() + g.height / 2;
|
|
70818
71114
|
case NoteYPosition.Bottom:
|
|
70819
|
-
case NoteYPosition.BottomWithStem:
|
|
70820
71115
|
return g.getBoundingBoxBottom();
|
|
71116
|
+
case NoteYPosition.BottomWithStem:
|
|
71117
|
+
return g.getBoundingBoxBottom() + this.renderer.smuflMetrics.getStemLength(Duration.Quarter, true);
|
|
70821
71118
|
}
|
|
70822
71119
|
}
|
|
70823
71120
|
return 0;
|
|
@@ -70900,10 +71197,18 @@ class ScoreBeatGlyph extends BeatOnNoteGlyphBase {
|
|
|
70900
71197
|
noteHeads.beat = this.container.beat;
|
|
70901
71198
|
const ghost = new GhostNoteContainerGlyph(false);
|
|
70902
71199
|
ghost.renderer = this.renderer;
|
|
70903
|
-
|
|
70904
|
-
|
|
70905
|
-
|
|
70906
|
-
|
|
71200
|
+
if (this.container.beat.slashed) {
|
|
71201
|
+
const steps = sr.heightLineCount - 1;
|
|
71202
|
+
const slash = new SlashNoteHeadGlyph(0, sr.getScoreY(steps), this.container.beat);
|
|
71203
|
+
slash.colorOverride = ElementStyleHelper.noteColor(sr.resources, NoteSubElement.StandardNotationNoteHead, this.container.beat.notes[0]);
|
|
71204
|
+
this.noteHeads.addMainNoteGlyph(slash, this.container.beat.notes[0], steps);
|
|
71205
|
+
}
|
|
71206
|
+
else {
|
|
71207
|
+
for (const note of this.container.beat.notes) {
|
|
71208
|
+
if (note.isVisible) {
|
|
71209
|
+
this._createNoteGlyph(note);
|
|
71210
|
+
ghost.addParenthesis(note);
|
|
71211
|
+
}
|
|
70907
71212
|
}
|
|
70908
71213
|
}
|
|
70909
71214
|
this.addNormal(noteHeads);
|
|
@@ -70932,6 +71237,24 @@ class ScoreBeatGlyph extends BeatOnNoteGlyphBase {
|
|
|
70932
71237
|
this.addEffect(group);
|
|
70933
71238
|
}
|
|
70934
71239
|
}
|
|
71240
|
+
if (this.renderer.bar.isMultiVoice) {
|
|
71241
|
+
let highestNotePosition = 0;
|
|
71242
|
+
let lowestNotePosition = 0;
|
|
71243
|
+
const direction = sr.getBeatDirection(this.container.beat);
|
|
71244
|
+
let offset = 0;
|
|
71245
|
+
if (this.container.beat.hasTuplet) {
|
|
71246
|
+
offset += sr.tupletOffset + sr.tupletSize;
|
|
71247
|
+
}
|
|
71248
|
+
if (direction === BeamDirection.Up) {
|
|
71249
|
+
highestNotePosition = this.getHighestNoteY(NoteYPosition.TopWithStem) - offset;
|
|
71250
|
+
lowestNotePosition = this.getLowestNoteY(NoteYPosition.Bottom);
|
|
71251
|
+
}
|
|
71252
|
+
else {
|
|
71253
|
+
highestNotePosition = this.getHighestNoteY(NoteYPosition.Top);
|
|
71254
|
+
lowestNotePosition = this.getLowestNoteY(NoteYPosition.BottomWithStem) + offset;
|
|
71255
|
+
}
|
|
71256
|
+
this.renderer.collisionHelper.reserveBeatSlot(this.container.beat, highestNotePosition, lowestNotePosition);
|
|
71257
|
+
}
|
|
70935
71258
|
}
|
|
70936
71259
|
_createRestGlyphs() {
|
|
70937
71260
|
const sr = this.renderer;
|
|
@@ -70998,9 +71321,6 @@ class ScoreBeatGlyph extends BeatOnNoteGlyphBase {
|
|
|
70998
71321
|
}
|
|
70999
71322
|
Logger.warning('Rendering', `No articulation found for percussion instrument ${n.percussionArticulation}`);
|
|
71000
71323
|
}
|
|
71001
|
-
if (n.beat.slashed) {
|
|
71002
|
-
return new SlashNoteHeadGlyph(0, 0, n.beat.duration, isGrace, n.beat);
|
|
71003
|
-
}
|
|
71004
71324
|
if (n.isDead) {
|
|
71005
71325
|
return new DeadNoteHeadGlyph(0, 0, isGrace);
|
|
71006
71326
|
}
|
|
@@ -71020,13 +71340,7 @@ class ScoreBeatGlyph extends BeatOnNoteGlyphBase {
|
|
|
71020
71340
|
const noteHeadGlyph = this._createNoteHeadGlyph(n);
|
|
71021
71341
|
noteHeadGlyph.colorOverride = ElementStyleHelper.noteColor(sr.resources, NoteSubElement.StandardNotationNoteHead, n);
|
|
71022
71342
|
// calculate y position
|
|
71023
|
-
let steps;
|
|
71024
|
-
if (n.beat.slashed) {
|
|
71025
|
-
steps = sr.heightLineCount - 1;
|
|
71026
|
-
}
|
|
71027
|
-
else {
|
|
71028
|
-
steps = sr.getNoteSteps(n);
|
|
71029
|
-
}
|
|
71343
|
+
let steps = sr.getNoteSteps(n);
|
|
71030
71344
|
noteHeadGlyph.y = sr.getScoreY(steps);
|
|
71031
71345
|
this.noteHeads.addMainNoteGlyph(noteHeadGlyph, n, steps);
|
|
71032
71346
|
if (!n.beat.slashed && n.harmonicType !== HarmonicType.None && n.harmonicType !== HarmonicType.Natural) {
|
|
@@ -71040,7 +71354,7 @@ class ScoreBeatGlyph extends BeatOnNoteGlyphBase {
|
|
|
71040
71354
|
}
|
|
71041
71355
|
const belowBeatEffects = this.noteHeads.belowBeatEffects;
|
|
71042
71356
|
const aboveBeatEffects = this.noteHeads.aboveBeatEffects;
|
|
71043
|
-
const outsideBeatEffects =
|
|
71357
|
+
const outsideBeatEffects = sr.getBeatDirection(this.container.beat) === BeamDirection.Up
|
|
71044
71358
|
? this.noteHeads.belowBeatEffects
|
|
71045
71359
|
: this.noteHeads.aboveBeatEffects;
|
|
71046
71360
|
if (n.isStaccato && !belowBeatEffects.has('Staccato')) {
|
|
@@ -71357,16 +71671,16 @@ class ScoreBendGlyph extends ScoreHelperNotesBaseGlyph {
|
|
|
71357
71671
|
switch (note.bendType) {
|
|
71358
71672
|
case BendType.Bend:
|
|
71359
71673
|
case BendType.PrebendBend:
|
|
71360
|
-
endY = this._endNoteGlyph.
|
|
71674
|
+
endY = this._endNoteGlyph.minStepsNote.glyph.getBoundingBoxTop();
|
|
71361
71675
|
endX = width;
|
|
71362
71676
|
break;
|
|
71363
71677
|
case BendType.BendRelease:
|
|
71364
|
-
endY = this._middleNoteGlyph.
|
|
71678
|
+
endY = this._middleNoteGlyph.minStepsNote.glyph.getBoundingBoxTop();
|
|
71365
71679
|
endX = width / 2;
|
|
71366
71680
|
break;
|
|
71367
71681
|
case BendType.Release:
|
|
71368
71682
|
case BendType.PrebendRelease:
|
|
71369
|
-
endY = this._endNoteGlyph.
|
|
71683
|
+
endY = this._endNoteGlyph.maxStepsNote.glyph.getBoundingBoxTop();
|
|
71370
71684
|
endX = width;
|
|
71371
71685
|
break;
|
|
71372
71686
|
}
|
|
@@ -72056,15 +72370,15 @@ class ScoreBeatContainerGlyph extends BeatContainerGlyph {
|
|
|
72056
72370
|
const beat = this.beat;
|
|
72057
72371
|
const isGrace = beat.graceType !== GraceType.None;
|
|
72058
72372
|
if (sr.hasFlag(beat)) {
|
|
72059
|
-
const direction =
|
|
72373
|
+
const direction = sr.getBeatDirection(beat);
|
|
72060
72374
|
const scale = isGrace ? EngravingSettings.GraceScale : 1;
|
|
72061
72375
|
const symbol = FlagGlyph.getSymbol(beat.duration, direction, isGrace);
|
|
72062
|
-
const flagWidth =
|
|
72376
|
+
const flagWidth = sr.smuflMetrics.glyphWidths.get(symbol) * scale;
|
|
72063
72377
|
this._flagStretch = flagWidth;
|
|
72064
72378
|
}
|
|
72065
72379
|
else if (isGrace) {
|
|
72066
72380
|
// always use flag size as spacing on grace notes
|
|
72067
|
-
const graceSpacing =
|
|
72381
|
+
const graceSpacing = sr.smuflMetrics.glyphWidths.get(MusicFontSymbol.Flag8thUp) * EngravingSettings.GraceScale;
|
|
72068
72382
|
this._flagStretch = graceSpacing;
|
|
72069
72383
|
}
|
|
72070
72384
|
super.doLayout();
|
|
@@ -72246,73 +72560,26 @@ class ScoreBarRenderer extends LineBarRenderer {
|
|
|
72246
72560
|
get tupletSubElement() {
|
|
72247
72561
|
return BeatSubElement.StandardNotationTuplet;
|
|
72248
72562
|
}
|
|
72249
|
-
_getSlashFlagY() {
|
|
72250
|
-
const line = (this.heightLineCount - 1) / 2;
|
|
72251
|
-
const slashY = this.getLineY(line);
|
|
72252
|
-
return slashY;
|
|
72253
|
-
}
|
|
72254
72563
|
getFlagTopY(beat, direction) {
|
|
72255
|
-
|
|
72256
|
-
|
|
72257
|
-
|
|
72258
|
-
const scale = beat.graceType !== GraceType.None ? EngravingSettings.GraceScale : 1;
|
|
72259
|
-
if (direction === BeamDirection.Down) {
|
|
72260
|
-
slashY -= this.smuflMetrics.stemDown.has(symbol)
|
|
72261
|
-
? this.smuflMetrics.stemDown.get(symbol).topY * scale
|
|
72262
|
-
: 0;
|
|
72263
|
-
}
|
|
72264
|
-
else {
|
|
72265
|
-
slashY -= this.smuflMetrics.stemUp.has(symbol)
|
|
72266
|
-
? this.smuflMetrics.stemUp.get(symbol).bottomY * scale
|
|
72267
|
-
: 0;
|
|
72268
|
-
if (!beat.isRest) {
|
|
72269
|
-
slashY -= this.smuflMetrics.standardStemLength + scale;
|
|
72270
|
-
}
|
|
72271
|
-
}
|
|
72272
|
-
return slashY;
|
|
72273
|
-
}
|
|
72274
|
-
const minNote = this.accidentalHelper.getMinStepsNote(beat);
|
|
72275
|
-
if (minNote) {
|
|
72276
|
-
return this.getNoteY(minNote, direction === BeamDirection.Up ? NoteYPosition.TopWithStem : NoteYPosition.StemDown);
|
|
72564
|
+
const position = direction === BeamDirection.Up ? NoteYPosition.TopWithStem : NoteYPosition.StemDown;
|
|
72565
|
+
if (beat.isRest) {
|
|
72566
|
+
return this.getRestY(beat, position);
|
|
72277
72567
|
}
|
|
72278
|
-
|
|
72279
|
-
|
|
72280
|
-
const scale = beat.graceType !== GraceType.None ? EngravingSettings.GraceScale : 1;
|
|
72281
|
-
y -= this.smuflMetrics.standardStemLength * scale;
|
|
72568
|
+
else {
|
|
72569
|
+
return this.voiceContainer.getHighestNoteY(beat, position);
|
|
72282
72570
|
}
|
|
72283
|
-
return y;
|
|
72284
72571
|
}
|
|
72285
72572
|
getFlagBottomY(beat, direction) {
|
|
72286
|
-
|
|
72287
|
-
|
|
72288
|
-
|
|
72289
|
-
const scale = beat.graceType !== GraceType.None ? EngravingSettings.GraceScale : 1;
|
|
72290
|
-
if (direction === BeamDirection.Down) {
|
|
72291
|
-
slashY -= this.smuflMetrics.stemDown.has(symbol)
|
|
72292
|
-
? this.smuflMetrics.stemDown.get(symbol).topY * scale
|
|
72293
|
-
: 0;
|
|
72294
|
-
slashY += this.smuflMetrics.standardStemLength + scale;
|
|
72295
|
-
}
|
|
72296
|
-
else {
|
|
72297
|
-
slashY -= this.smuflMetrics.stemUp.has(symbol)
|
|
72298
|
-
? this.smuflMetrics.stemUp.get(symbol).bottomY * scale
|
|
72299
|
-
: 0;
|
|
72300
|
-
}
|
|
72301
|
-
return slashY;
|
|
72302
|
-
}
|
|
72303
|
-
const maxNote = this.accidentalHelper.getMaxStepsNote(beat);
|
|
72304
|
-
if (maxNote) {
|
|
72305
|
-
return this.getNoteY(maxNote, direction === BeamDirection.Up ? NoteYPosition.StemUp : NoteYPosition.BottomWithStem);
|
|
72573
|
+
const position = direction === BeamDirection.Up ? NoteYPosition.StemUp : NoteYPosition.BottomWithStem;
|
|
72574
|
+
if (beat.isRest) {
|
|
72575
|
+
return this.getRestY(beat, position);
|
|
72306
72576
|
}
|
|
72307
|
-
|
|
72308
|
-
|
|
72309
|
-
const scale = beat.graceType !== GraceType.None ? EngravingSettings.GraceScale : 1;
|
|
72310
|
-
y += this.smuflMetrics.standardStemLength * scale;
|
|
72577
|
+
else {
|
|
72578
|
+
return this.voiceContainer.getLowestNoteY(beat, position);
|
|
72311
72579
|
}
|
|
72312
|
-
return y;
|
|
72313
72580
|
}
|
|
72314
72581
|
getBeamDirection(helper) {
|
|
72315
|
-
return helper.
|
|
72582
|
+
return this._beamDirections.has(helper) ? this._beamDirections.get(helper) : BeamDirection.Up;
|
|
72316
72583
|
}
|
|
72317
72584
|
centerStaffStemY(direction) {
|
|
72318
72585
|
const isStandardFive = this.bar.staff.standardNotationLineCount === Staff.DefaultStandardNotationLineCount;
|
|
@@ -72326,50 +72593,9 @@ class ScoreBarRenderer extends LineBarRenderer {
|
|
|
72326
72593
|
}
|
|
72327
72594
|
return this.getScoreY(0);
|
|
72328
72595
|
}
|
|
72329
|
-
getStemBottomY(_beamingHelper) {
|
|
72330
|
-
throw new Error('Method not implemented.');
|
|
72331
|
-
}
|
|
72332
72596
|
get middleYPosition() {
|
|
72333
72597
|
return this.getScoreY(this.bar.staff.standardNotationLineCount - 1);
|
|
72334
72598
|
}
|
|
72335
|
-
getNoteY(note, requestedPosition) {
|
|
72336
|
-
if (note.beat.slashed) {
|
|
72337
|
-
const line = (this.heightLineCount - 1) / 2;
|
|
72338
|
-
return this.getLineY(line);
|
|
72339
|
-
}
|
|
72340
|
-
let y = super.getNoteY(note, requestedPosition);
|
|
72341
|
-
if (Number.isNaN(y)) {
|
|
72342
|
-
// NOTE: some might request the note position before the glyphs have been created
|
|
72343
|
-
// e.g. the beaming helper, for these we just need a rough
|
|
72344
|
-
// estimate on the position
|
|
72345
|
-
const steps = AccidentalHelper.computeStepsWithoutAccidentals(this.bar, note);
|
|
72346
|
-
y = this.getScoreY(steps);
|
|
72347
|
-
const scale = note.beat.graceType === GraceType.None ? 1 : EngravingSettings.GraceScale;
|
|
72348
|
-
const stemHeight = this.smuflMetrics.standardStemLength * scale;
|
|
72349
|
-
const noteHeadHeight = this.smuflMetrics.glyphHeights.get(NoteHeadGlyph.getSymbol(note.beat.duration)) * scale;
|
|
72350
|
-
switch (requestedPosition) {
|
|
72351
|
-
case NoteYPosition.TopWithStem:
|
|
72352
|
-
y -= stemHeight;
|
|
72353
|
-
break;
|
|
72354
|
-
case NoteYPosition.Top:
|
|
72355
|
-
y -= noteHeadHeight / 2;
|
|
72356
|
-
break;
|
|
72357
|
-
case NoteYPosition.Center:
|
|
72358
|
-
break;
|
|
72359
|
-
case NoteYPosition.Bottom:
|
|
72360
|
-
y += noteHeadHeight / 2;
|
|
72361
|
-
break;
|
|
72362
|
-
case NoteYPosition.BottomWithStem:
|
|
72363
|
-
y += stemHeight;
|
|
72364
|
-
break;
|
|
72365
|
-
case NoteYPosition.StemUp:
|
|
72366
|
-
break;
|
|
72367
|
-
case NoteYPosition.StemDown:
|
|
72368
|
-
break;
|
|
72369
|
-
}
|
|
72370
|
-
}
|
|
72371
|
-
return y;
|
|
72372
|
-
}
|
|
72373
72599
|
applyLayoutingInfo() {
|
|
72374
72600
|
const result = super.applyLayoutingInfo();
|
|
72375
72601
|
if (result && this.bar.isMultiVoice) {
|
|
@@ -72386,34 +72612,6 @@ class ScoreBarRenderer extends LineBarRenderer {
|
|
|
72386
72612
|
}
|
|
72387
72613
|
return result;
|
|
72388
72614
|
}
|
|
72389
|
-
calculateBeamYWithDirection(h, x, direction) {
|
|
72390
|
-
if (h.beats.length === 0) {
|
|
72391
|
-
return direction === BeamDirection.Up
|
|
72392
|
-
? this.getFlagTopY(h.beats[0], direction)
|
|
72393
|
-
: this.getFlagBottomY(h.beats[0], direction);
|
|
72394
|
-
}
|
|
72395
|
-
this.ensureBeamDrawingInfo(h, direction);
|
|
72396
|
-
return h.drawingInfos.get(direction).calcY(x);
|
|
72397
|
-
}
|
|
72398
|
-
getBarLineStart(beat, direction) {
|
|
72399
|
-
if (beat.slashed) {
|
|
72400
|
-
return direction === BeamDirection.Down
|
|
72401
|
-
? this.getFlagTopY(beat, direction)
|
|
72402
|
-
: this.getFlagBottomY(beat, direction);
|
|
72403
|
-
}
|
|
72404
|
-
if (direction === BeamDirection.Up) {
|
|
72405
|
-
const maxNote = this.accidentalHelper.getMaxStepsNote(beat);
|
|
72406
|
-
if (maxNote) {
|
|
72407
|
-
return this.getNoteY(maxNote, NoteYPosition.StemUp);
|
|
72408
|
-
}
|
|
72409
|
-
return this.getScoreY(this.accidentalHelper.getMaxSteps(beat));
|
|
72410
|
-
}
|
|
72411
|
-
const minNote = this.accidentalHelper.getMinStepsNote(beat);
|
|
72412
|
-
if (minNote) {
|
|
72413
|
-
return this.getNoteY(minNote, NoteYPosition.StemDown);
|
|
72414
|
-
}
|
|
72415
|
-
return this.getScoreY(this.accidentalHelper.getMinSteps(beat));
|
|
72416
|
-
}
|
|
72417
72615
|
getMinLineOfBeat(beat) {
|
|
72418
72616
|
return this.accidentalHelper.getMinSteps(beat) / 2;
|
|
72419
72617
|
}
|
|
@@ -72555,27 +72753,62 @@ class ScoreBarRenderer extends LineBarRenderer {
|
|
|
72555
72753
|
getNoteSteps(n) {
|
|
72556
72754
|
return this.accidentalHelper.getNoteSteps(n);
|
|
72557
72755
|
}
|
|
72756
|
+
_beamDirections = new Map();
|
|
72558
72757
|
completeBeamingHelper(helper) {
|
|
72559
|
-
|
|
72560
|
-
|
|
72561
|
-
|
|
72562
|
-
|
|
72563
|
-
|
|
72564
|
-
|
|
72565
|
-
|
|
72566
|
-
|
|
72567
|
-
|
|
72568
|
-
|
|
72569
|
-
|
|
72570
|
-
|
|
72571
|
-
|
|
72572
|
-
|
|
72573
|
-
|
|
72574
|
-
|
|
72575
|
-
|
|
72576
|
-
|
|
72577
|
-
|
|
72578
|
-
|
|
72758
|
+
const direction = this._calculateBeamDirection(helper);
|
|
72759
|
+
this._beamDirections.set(helper, direction);
|
|
72760
|
+
}
|
|
72761
|
+
_calculateBeamDirection(helper) {
|
|
72762
|
+
// no proper voice (should not happen usually)
|
|
72763
|
+
if (!helper.voice) {
|
|
72764
|
+
return BeamDirection.Up;
|
|
72765
|
+
}
|
|
72766
|
+
// we have a preferred direction
|
|
72767
|
+
if (helper.preferredBeamDirection !== null) {
|
|
72768
|
+
return helper.preferredBeamDirection;
|
|
72769
|
+
}
|
|
72770
|
+
// on multi-voice setups secondary voices are always down
|
|
72771
|
+
if (helper.voice.index > 0) {
|
|
72772
|
+
return this._invertBeamDirection(helper, BeamDirection.Down);
|
|
72773
|
+
}
|
|
72774
|
+
// on multi-voice setups primary voices are always up
|
|
72775
|
+
if (helper.voice.bar.isMultiVoice) {
|
|
72776
|
+
return this._invertBeamDirection(helper, BeamDirection.Up);
|
|
72777
|
+
}
|
|
72778
|
+
// grace notes are always up
|
|
72779
|
+
if (helper.beats[0].graceType !== GraceType.None) {
|
|
72780
|
+
return this._invertBeamDirection(helper, BeamDirection.Up);
|
|
72781
|
+
}
|
|
72782
|
+
if (helper.beats.length === 1 && helper.beats[0].slashed) {
|
|
72783
|
+
return this._invertBeamDirection(helper, BeamDirection.Down);
|
|
72784
|
+
}
|
|
72785
|
+
// the average line is used for determination
|
|
72786
|
+
// key lowerequal than middle line -> up
|
|
72787
|
+
// key higher than middle line -> down
|
|
72788
|
+
if (helper.highestNoteInHelper && helper.lowestNoteInHelper) {
|
|
72789
|
+
// NOTE: This is the only place where we need the locations before we have positioned the notes
|
|
72790
|
+
// TODO: we should first register all note-heads and calculate the accidentals+steps
|
|
72791
|
+
const highestNotePosition = this._getNoteCenterYBeforeLayouting(helper.highestNoteInHelper);
|
|
72792
|
+
const lowestNotePosition = this._getNoteCenterYBeforeLayouting(helper.lowestNoteInHelper);
|
|
72793
|
+
const avg = (highestNotePosition + lowestNotePosition) / 2;
|
|
72794
|
+
return this._invertBeamDirection(helper, this.middleYPosition < avg ? BeamDirection.Up : BeamDirection.Down);
|
|
72795
|
+
}
|
|
72796
|
+
return this._invertBeamDirection(helper, BeamDirection.Up);
|
|
72797
|
+
}
|
|
72798
|
+
_getNoteCenterYBeforeLayouting(note) {
|
|
72799
|
+
const steps = AccidentalHelper.computeStepsWithoutAccidentals(this.bar, note);
|
|
72800
|
+
return this.getScoreY(steps);
|
|
72801
|
+
}
|
|
72802
|
+
_invertBeamDirection(helper, direction) {
|
|
72803
|
+
if (!helper.invertBeamDirection) {
|
|
72804
|
+
return direction;
|
|
72805
|
+
}
|
|
72806
|
+
switch (direction) {
|
|
72807
|
+
case BeamDirection.Down:
|
|
72808
|
+
return BeamDirection.Up;
|
|
72809
|
+
// case BeamDirection.Up:
|
|
72810
|
+
default:
|
|
72811
|
+
return BeamDirection.Down;
|
|
72579
72812
|
}
|
|
72580
72813
|
}
|
|
72581
72814
|
paintBeamingStem(beat, _cy, x, topY, bottomY, canvas) {
|
|
@@ -72618,6 +72851,8 @@ class SlashRestGlyph extends ScoreRestGlyph {
|
|
|
72618
72851
|
* @internal
|
|
72619
72852
|
*/
|
|
72620
72853
|
class SlashBeatGlyph extends BeatOnNoteGlyphBase {
|
|
72854
|
+
_tremoloPicking;
|
|
72855
|
+
_stemLengthExtension = 0;
|
|
72621
72856
|
noteHeads = null;
|
|
72622
72857
|
deadSlapped = null;
|
|
72623
72858
|
restGlyph = null;
|
|
@@ -72660,17 +72895,18 @@ class SlashBeatGlyph extends BeatOnNoteGlyphBase {
|
|
|
72660
72895
|
beatBounds.addNote(noteBounds);
|
|
72661
72896
|
}
|
|
72662
72897
|
}
|
|
72663
|
-
getLowestNoteY() {
|
|
72664
|
-
return this.
|
|
72898
|
+
getLowestNoteY(requestedPosition) {
|
|
72899
|
+
return this._internalGetNoteY(requestedPosition);
|
|
72665
72900
|
}
|
|
72666
|
-
getHighestNoteY() {
|
|
72667
|
-
return this.
|
|
72901
|
+
getHighestNoteY(requestedPosition) {
|
|
72902
|
+
return this._internalGetNoteY(requestedPosition);
|
|
72668
72903
|
}
|
|
72669
72904
|
getRestY(requestedPosition) {
|
|
72670
72905
|
const g = this.restGlyph;
|
|
72671
72906
|
if (g) {
|
|
72672
72907
|
switch (requestedPosition) {
|
|
72673
72908
|
case NoteYPosition.TopWithStem:
|
|
72909
|
+
return g.getBoundingBoxTop() - this.renderer.smuflMetrics.getStemLength(Duration.Quarter, true);
|
|
72674
72910
|
case NoteYPosition.Top:
|
|
72675
72911
|
return g.getBoundingBoxTop();
|
|
72676
72912
|
case NoteYPosition.Center:
|
|
@@ -72678,35 +72914,70 @@ class SlashBeatGlyph extends BeatOnNoteGlyphBase {
|
|
|
72678
72914
|
case NoteYPosition.StemDown:
|
|
72679
72915
|
return g.getBoundingBoxTop() + g.height / 2;
|
|
72680
72916
|
case NoteYPosition.Bottom:
|
|
72681
|
-
case NoteYPosition.BottomWithStem:
|
|
72682
72917
|
return g.getBoundingBoxBottom();
|
|
72918
|
+
case NoteYPosition.BottomWithStem:
|
|
72919
|
+
return g.getBoundingBoxBottom() + this.renderer.smuflMetrics.getStemLength(Duration.Quarter, true);
|
|
72683
72920
|
}
|
|
72684
72921
|
}
|
|
72685
72922
|
return 0;
|
|
72686
72923
|
}
|
|
72687
|
-
getNoteY(
|
|
72924
|
+
getNoteY(_note, requestedPosition) {
|
|
72925
|
+
return this._internalGetNoteY(requestedPosition);
|
|
72926
|
+
}
|
|
72927
|
+
_internalGetNoteY(requestedPosition) {
|
|
72688
72928
|
let g = null;
|
|
72689
72929
|
let symbol = MusicFontSymbol.None;
|
|
72930
|
+
let hasStem = false;
|
|
72690
72931
|
if (this.noteHeads) {
|
|
72691
72932
|
g = this.noteHeads;
|
|
72692
|
-
symbol = SlashNoteHeadGlyph.getSymbol(
|
|
72933
|
+
symbol = SlashNoteHeadGlyph.getSymbol(this.container.beat.duration);
|
|
72934
|
+
hasStem = true;
|
|
72693
72935
|
}
|
|
72694
72936
|
else if (this.deadSlapped) {
|
|
72695
72937
|
g = this.deadSlapped;
|
|
72696
72938
|
}
|
|
72697
72939
|
if (g) {
|
|
72698
72940
|
let pos = this.y + g.y;
|
|
72941
|
+
const sr = this.renderer;
|
|
72942
|
+
const beat = this.container.beat;
|
|
72943
|
+
const scale = beat.graceType !== GraceType.None ? EngravingSettings.GraceScale : 1;
|
|
72699
72944
|
switch (requestedPosition) {
|
|
72700
|
-
case NoteYPosition.Top:
|
|
72701
72945
|
case NoteYPosition.TopWithStem:
|
|
72946
|
+
if (hasStem) {
|
|
72947
|
+
// stem start
|
|
72948
|
+
pos -=
|
|
72949
|
+
(sr.smuflMetrics.stemUp.has(symbol) ? sr.smuflMetrics.stemUp.get(symbol).bottomY : 0) *
|
|
72950
|
+
scale;
|
|
72951
|
+
// stem size according to duration
|
|
72952
|
+
pos -= sr.smuflMetrics.getStemLength(beat.duration, sr.hasFlag(beat)) * scale;
|
|
72953
|
+
pos -= this._stemLengthExtension;
|
|
72954
|
+
}
|
|
72955
|
+
else {
|
|
72956
|
+
pos -= g.height / 2;
|
|
72957
|
+
}
|
|
72958
|
+
return pos;
|
|
72959
|
+
case NoteYPosition.Top:
|
|
72702
72960
|
pos -= g.height / 2;
|
|
72703
72961
|
break;
|
|
72704
72962
|
case NoteYPosition.Center:
|
|
72705
72963
|
break;
|
|
72706
72964
|
case NoteYPosition.Bottom:
|
|
72707
|
-
case NoteYPosition.BottomWithStem:
|
|
72708
72965
|
pos += g.height / 2;
|
|
72709
72966
|
break;
|
|
72967
|
+
case NoteYPosition.BottomWithStem:
|
|
72968
|
+
if (hasStem) {
|
|
72969
|
+
pos -=
|
|
72970
|
+
(sr.smuflMetrics.stemDown.has(symbol)
|
|
72971
|
+
? sr.smuflMetrics.stemDown.get(symbol).topY
|
|
72972
|
+
: -sr.smuflMetrics.glyphHeights.get(symbol) / 2) * scale;
|
|
72973
|
+
// stem size according to duration
|
|
72974
|
+
pos += sr.smuflMetrics.getStemLength(beat.duration, sr.hasFlag(beat)) * scale;
|
|
72975
|
+
pos += this._stemLengthExtension;
|
|
72976
|
+
}
|
|
72977
|
+
else {
|
|
72978
|
+
pos += g.height / 2;
|
|
72979
|
+
}
|
|
72980
|
+
return pos;
|
|
72710
72981
|
case NoteYPosition.StemUp:
|
|
72711
72982
|
pos -= this.renderer.smuflMetrics.stemUp.has(symbol)
|
|
72712
72983
|
? this.renderer.smuflMetrics.stemUp.get(symbol).bottomY
|
|
@@ -72735,11 +73006,16 @@ class SlashBeatGlyph extends BeatOnNoteGlyphBase {
|
|
|
72735
73006
|
}
|
|
72736
73007
|
else if (!this.container.beat.isEmpty) {
|
|
72737
73008
|
if (!this.container.beat.isRest) {
|
|
72738
|
-
const
|
|
72739
|
-
const noteHeadGlyph = new SlashNoteHeadGlyph(0, glyphY, this.container.beat.duration, isGrace, this.container.beat);
|
|
73009
|
+
const noteHeadGlyph = new SlashNoteHeadGlyph(0, glyphY, this.container.beat);
|
|
72740
73010
|
this.noteHeads = noteHeadGlyph;
|
|
72741
73011
|
noteHeadGlyph.beat = this.container.beat;
|
|
72742
73012
|
this.addNormal(noteHeadGlyph);
|
|
73013
|
+
if (this.container.beat.isTremolo) {
|
|
73014
|
+
this._tremoloPicking = new TremoloPickingGlyph(0, 0, this.container.beat.tremoloPicking);
|
|
73015
|
+
this._tremoloPicking.renderer = this.renderer;
|
|
73016
|
+
this._tremoloPicking.doLayout();
|
|
73017
|
+
this._alignTremoloPickingGlyph();
|
|
73018
|
+
}
|
|
72743
73019
|
}
|
|
72744
73020
|
else {
|
|
72745
73021
|
const restGlyph = new SlashRestGlyph(0, glyphY, this.container.beat.duration);
|
|
@@ -72774,6 +73050,27 @@ class SlashBeatGlyph extends BeatOnNoteGlyphBase {
|
|
|
72774
73050
|
this.stemX = this.onTimeX;
|
|
72775
73051
|
}
|
|
72776
73052
|
this.middleX = this.onTimeX;
|
|
73053
|
+
const tremolo = this._tremoloPicking;
|
|
73054
|
+
if (tremolo) {
|
|
73055
|
+
tremolo.x = this.container.beat.duration < Duration.Half ? this.width / 2 : this.stemX;
|
|
73056
|
+
}
|
|
73057
|
+
}
|
|
73058
|
+
_alignTremoloPickingGlyph() {
|
|
73059
|
+
const g = this._tremoloPicking;
|
|
73060
|
+
g.alignTremoloPickingGlyph(BeamDirection.Up, this._internalGetNoteY(NoteYPosition.TopWithStem), this._internalGetNoteY(NoteYPosition.Center), this.container.beat.duration);
|
|
73061
|
+
this._stemLengthExtension = g.stemExtensionHeight;
|
|
73062
|
+
let tremoloX = this.stemX;
|
|
73063
|
+
if (this.container.beat.duration < Duration.Half) {
|
|
73064
|
+
tremoloX = this.width / 2;
|
|
73065
|
+
}
|
|
73066
|
+
g.x = tremoloX;
|
|
73067
|
+
}
|
|
73068
|
+
paint(cx, cy, canvas) {
|
|
73069
|
+
super.paint(cx, cy, canvas);
|
|
73070
|
+
const tremolo = this._tremoloPicking;
|
|
73071
|
+
if (tremolo) {
|
|
73072
|
+
tremolo.paint(cx + this.x, cy + this.y, canvas);
|
|
73073
|
+
}
|
|
72777
73074
|
}
|
|
72778
73075
|
}
|
|
72779
73076
|
|
|
@@ -72808,15 +73105,15 @@ class SlashBeatContainerGlyph extends BeatContainerGlyph {
|
|
|
72808
73105
|
const beat = this.beat;
|
|
72809
73106
|
const isGrace = beat.graceType !== GraceType.None;
|
|
72810
73107
|
if (sr.hasFlag(beat)) {
|
|
72811
|
-
const direction =
|
|
73108
|
+
const direction = sr.getBeatDirection(beat);
|
|
72812
73109
|
const scale = isGrace ? EngravingSettings.GraceScale : 1;
|
|
72813
73110
|
const symbol = FlagGlyph.getSymbol(beat.duration, direction, isGrace);
|
|
72814
|
-
const flagWidth =
|
|
73111
|
+
const flagWidth = sr.smuflMetrics.glyphWidths.get(symbol) * scale;
|
|
72815
73112
|
this._flagStretch = flagWidth;
|
|
72816
73113
|
}
|
|
72817
73114
|
else if (isGrace) {
|
|
72818
73115
|
// always use flag size as spacing on grace notes
|
|
72819
|
-
const graceSpacing =
|
|
73116
|
+
const graceSpacing = sr.smuflMetrics.glyphWidths.get(MusicFontSymbol.Flag8thUp) * EngravingSettings.GraceScale;
|
|
72820
73117
|
this._flagStretch = graceSpacing;
|
|
72821
73118
|
}
|
|
72822
73119
|
super.doLayout();
|
|
@@ -72903,45 +73200,26 @@ class SlashBarRenderer extends LineBarRenderer {
|
|
|
72903
73200
|
getNoteLine(_note) {
|
|
72904
73201
|
return 0;
|
|
72905
73202
|
}
|
|
72906
|
-
getFlagTopY(beat,
|
|
72907
|
-
|
|
72908
|
-
|
|
72909
|
-
|
|
72910
|
-
slashY -= this.smuflMetrics.stemUp.has(symbol) ? this.smuflMetrics.stemUp.get(symbol).bottomY * scale : 0;
|
|
72911
|
-
if (!beat.isRest) {
|
|
72912
|
-
slashY -= this.smuflMetrics.standardStemLength + scale;
|
|
73203
|
+
getFlagTopY(beat, direction) {
|
|
73204
|
+
const position = direction === BeamDirection.Up ? NoteYPosition.TopWithStem : NoteYPosition.StemDown;
|
|
73205
|
+
if (beat.notes.length > 0) {
|
|
73206
|
+
return this.getNoteY(beat.notes[0], position);
|
|
72913
73207
|
}
|
|
72914
|
-
|
|
72915
|
-
|
|
72916
|
-
getFlagBottomY(beat, _direction) {
|
|
72917
|
-
let slashY = this.getLineY(0);
|
|
72918
|
-
const symbol = SlashNoteHeadGlyph.getSymbol(beat.duration);
|
|
72919
|
-
const scale = beat.graceType !== GraceType.None ? EngravingSettings.GraceScale : 1;
|
|
72920
|
-
slashY -= this.smuflMetrics.stemUp.has(symbol) ? this.smuflMetrics.stemUp.get(symbol).bottomY * scale : 0;
|
|
72921
|
-
return slashY;
|
|
72922
|
-
}
|
|
72923
|
-
getBeamDirection(_helper) {
|
|
72924
|
-
return BeamDirection.Up;
|
|
72925
|
-
}
|
|
72926
|
-
getNoteY(note, requestedPosition) {
|
|
72927
|
-
let y = super.getNoteY(note, requestedPosition);
|
|
72928
|
-
if (Number.isNaN(y)) {
|
|
72929
|
-
y = this.getLineY(0);
|
|
73208
|
+
else {
|
|
73209
|
+
return this.getRestY(beat, position);
|
|
72930
73210
|
}
|
|
72931
|
-
return y;
|
|
72932
73211
|
}
|
|
72933
|
-
|
|
72934
|
-
|
|
72935
|
-
|
|
72936
|
-
|
|
72937
|
-
|
|
73212
|
+
getFlagBottomY(beat, direction) {
|
|
73213
|
+
const position = direction === BeamDirection.Up ? NoteYPosition.StemUp : NoteYPosition.BottomWithStem;
|
|
73214
|
+
if (beat.notes.length > 0) {
|
|
73215
|
+
return this.getNoteY(beat.notes[0], position);
|
|
73216
|
+
}
|
|
73217
|
+
else {
|
|
73218
|
+
return this.getRestY(beat, position);
|
|
72938
73219
|
}
|
|
72939
|
-
this.ensureBeamDrawingInfo(h, direction);
|
|
72940
|
-
return h.drawingInfos.get(direction).calcY(x);
|
|
72941
73220
|
}
|
|
72942
|
-
|
|
72943
|
-
|
|
72944
|
-
return this.getLineY(0) - noteHeadHeight / 2;
|
|
73221
|
+
getBeamDirection(_helper) {
|
|
73222
|
+
return BeamDirection.Up;
|
|
72945
73223
|
}
|
|
72946
73224
|
createLinePreBeatGlyphs() {
|
|
72947
73225
|
// Key signature
|
|
@@ -72985,6 +73263,9 @@ class SlashBarRenderer extends LineBarRenderer {
|
|
|
72985
73263
|
}
|
|
72986
73264
|
this.calculateBeamingOverflows(rendererTop, rendererBottom);
|
|
72987
73265
|
}
|
|
73266
|
+
shouldPaintBeamingHelper(h) {
|
|
73267
|
+
return super.shouldPaintBeamingHelper(h) && h.voice.index === 0;
|
|
73268
|
+
}
|
|
72988
73269
|
paintBeamingStem(beat, _cy, x, topY, bottomY, canvas) {
|
|
72989
73270
|
const _ = ElementStyleHelper.beat(canvas, BeatSubElement.SlashStem, beat);
|
|
72990
73271
|
try {
|
|
@@ -73031,6 +73312,15 @@ class NoteNumberGlyph extends Glyph {
|
|
|
73031
73312
|
super(x, y);
|
|
73032
73313
|
this._note = note;
|
|
73033
73314
|
}
|
|
73315
|
+
get _padding() {
|
|
73316
|
+
return this.renderer.lineSpacing * 0.25;
|
|
73317
|
+
}
|
|
73318
|
+
getBoundingBoxTop() {
|
|
73319
|
+
return this.y - this.height / 2 - this._padding;
|
|
73320
|
+
}
|
|
73321
|
+
getBoundingBoxBottom() {
|
|
73322
|
+
return this.y + this.height / 2;
|
|
73323
|
+
}
|
|
73034
73324
|
doLayout() {
|
|
73035
73325
|
const n = this._note;
|
|
73036
73326
|
let fret = n.fret - n.beat.voice.bar.staff.transpositionPitch;
|
|
@@ -73105,11 +73395,12 @@ class NoteNumberGlyph extends Glyph {
|
|
|
73105
73395
|
return;
|
|
73106
73396
|
}
|
|
73107
73397
|
const textWidth = this.noteStringWidth + this._trillNoteStringWidth;
|
|
73108
|
-
const x =
|
|
73109
|
-
|
|
73398
|
+
const x = cx + this.x + (this.width - textWidth) / 2;
|
|
73399
|
+
const y = cy + this.y;
|
|
73400
|
+
this.paintTrill(x, y, canvas);
|
|
73110
73401
|
const _ = ElementStyleHelper.note(canvas, NoteSubElement.GuitarTabFretNumber, this._note);
|
|
73111
73402
|
try {
|
|
73112
|
-
canvas.fillText(this._noteString, x,
|
|
73403
|
+
canvas.fillText(this._noteString, x, y);
|
|
73113
73404
|
}
|
|
73114
73405
|
finally {
|
|
73115
73406
|
_?.[Symbol.dispose]?.();
|
|
@@ -73120,7 +73411,7 @@ class NoteNumberGlyph extends Glyph {
|
|
|
73120
73411
|
try {
|
|
73121
73412
|
const prevFont = this.renderer.scoreRenderer.canvas.font;
|
|
73122
73413
|
this.renderer.scoreRenderer.canvas.font = this.renderer.resources.graceFont;
|
|
73123
|
-
canvas.fillText(this._trillNoteString, x + this.noteStringWidth, cy
|
|
73414
|
+
canvas.fillText(this._trillNoteString, x + this.noteStringWidth, cy);
|
|
73124
73415
|
this.renderer.scoreRenderer.canvas.font = prevFont;
|
|
73125
73416
|
}
|
|
73126
73417
|
finally {
|
|
@@ -73179,11 +73470,11 @@ class TabNoteChordGlyph extends Glyph {
|
|
|
73179
73470
|
}
|
|
73180
73471
|
return 0;
|
|
73181
73472
|
}
|
|
73182
|
-
getLowestNoteY() {
|
|
73183
|
-
return this.maxStringNote ? this.getNoteY(this.maxStringNote,
|
|
73473
|
+
getLowestNoteY(requestedPosition) {
|
|
73474
|
+
return this.maxStringNote ? this.getNoteY(this.maxStringNote, requestedPosition) : 0;
|
|
73184
73475
|
}
|
|
73185
|
-
getHighestNoteY() {
|
|
73186
|
-
return this.minStringNote ? this.getNoteY(this.minStringNote,
|
|
73476
|
+
getHighestNoteY(requestedPosition) {
|
|
73477
|
+
return this.minStringNote ? this.getNoteY(this.minStringNote, requestedPosition) : 0;
|
|
73187
73478
|
}
|
|
73188
73479
|
getNoteY(note, requestedPosition) {
|
|
73189
73480
|
if (this.notesPerString.has(note.string)) {
|
|
@@ -73191,23 +73482,44 @@ class TabNoteChordGlyph extends Glyph {
|
|
|
73191
73482
|
let pos = this.y + n.y;
|
|
73192
73483
|
switch (requestedPosition) {
|
|
73193
73484
|
case NoteYPosition.Top:
|
|
73194
|
-
case NoteYPosition.TopWithStem:
|
|
73195
73485
|
pos -= n.height / 2;
|
|
73196
73486
|
break;
|
|
73487
|
+
case NoteYPosition.StemUp:
|
|
73488
|
+
pos = this.y + n.getBoundingBoxTop();
|
|
73489
|
+
break;
|
|
73197
73490
|
case NoteYPosition.Center:
|
|
73198
73491
|
break;
|
|
73199
73492
|
case NoteYPosition.Bottom:
|
|
73200
|
-
case NoteYPosition.BottomWithStem:
|
|
73201
73493
|
pos += n.height / 2;
|
|
73202
73494
|
break;
|
|
73203
|
-
case NoteYPosition.StemUp:
|
|
73204
73495
|
case NoteYPosition.StemDown:
|
|
73496
|
+
pos = this.y + n.getBoundingBoxBottom();
|
|
73497
|
+
break;
|
|
73498
|
+
case NoteYPosition.TopWithStem:
|
|
73499
|
+
pos = -this.renderer.settings.notation.rhythmHeight;
|
|
73500
|
+
pos -= this.calculateTremoloHeightForStem();
|
|
73501
|
+
break;
|
|
73502
|
+
case NoteYPosition.BottomWithStem:
|
|
73503
|
+
pos = this.renderer.height + this.renderer.settings.notation.rhythmHeight;
|
|
73504
|
+
pos += this.calculateTremoloHeightForStem();
|
|
73205
73505
|
break;
|
|
73206
73506
|
}
|
|
73207
73507
|
return pos;
|
|
73208
73508
|
}
|
|
73209
73509
|
return 0;
|
|
73210
73510
|
}
|
|
73511
|
+
calculateTremoloHeightForStem() {
|
|
73512
|
+
const beat = this.beat;
|
|
73513
|
+
if (!beat.isTremolo) {
|
|
73514
|
+
return 0;
|
|
73515
|
+
}
|
|
73516
|
+
if (beat.duration <= Duration.Quarter) {
|
|
73517
|
+
return 0;
|
|
73518
|
+
}
|
|
73519
|
+
const symbol = TremoloPickingGlyph._getSymbol(beat.tremoloPicking);
|
|
73520
|
+
const smufl = this.renderer.smuflMetrics;
|
|
73521
|
+
return smufl.glyphHeights.has(symbol) ? smufl.glyphHeights.get(symbol) : 0;
|
|
73522
|
+
}
|
|
73211
73523
|
doLayout() {
|
|
73212
73524
|
let w = 0;
|
|
73213
73525
|
if (this.beat.deadSlapped) {
|
|
@@ -73333,6 +73645,20 @@ class TabBeatGlyph extends BeatOnNoteGlyphBase {
|
|
|
73333
73645
|
return BeatSubElement.GuitarTabEffects;
|
|
73334
73646
|
}
|
|
73335
73647
|
getNoteX(note, requestedPosition) {
|
|
73648
|
+
if (this.slash) {
|
|
73649
|
+
let pos = this.slash.x;
|
|
73650
|
+
switch (requestedPosition) {
|
|
73651
|
+
case NoteXPosition.Left:
|
|
73652
|
+
break;
|
|
73653
|
+
case NoteXPosition.Center:
|
|
73654
|
+
pos += this.slash.width / 2;
|
|
73655
|
+
break;
|
|
73656
|
+
case NoteXPosition.Right:
|
|
73657
|
+
pos += this.slash.width;
|
|
73658
|
+
break;
|
|
73659
|
+
}
|
|
73660
|
+
return pos;
|
|
73661
|
+
}
|
|
73336
73662
|
return this.noteNumbers ? this.noteNumbers.getNoteX(note, requestedPosition) : 0;
|
|
73337
73663
|
}
|
|
73338
73664
|
getNoteY(note, requestedPosition) {
|
|
@@ -73343,6 +73669,7 @@ class TabBeatGlyph extends BeatOnNoteGlyphBase {
|
|
|
73343
73669
|
if (g) {
|
|
73344
73670
|
switch (requestedPosition) {
|
|
73345
73671
|
case NoteYPosition.TopWithStem:
|
|
73672
|
+
return g.getBoundingBoxTop() - this.renderer.smuflMetrics.getStemLength(Duration.Quarter, true);
|
|
73346
73673
|
case NoteYPosition.Top:
|
|
73347
73674
|
return g.getBoundingBoxTop();
|
|
73348
73675
|
case NoteYPosition.Center:
|
|
@@ -73350,17 +73677,18 @@ class TabBeatGlyph extends BeatOnNoteGlyphBase {
|
|
|
73350
73677
|
case NoteYPosition.StemDown:
|
|
73351
73678
|
return g.getBoundingBoxTop() + g.height / 2;
|
|
73352
73679
|
case NoteYPosition.Bottom:
|
|
73680
|
+
return g.getBoundingBoxTop();
|
|
73353
73681
|
case NoteYPosition.BottomWithStem:
|
|
73354
|
-
return g.getBoundingBoxBottom();
|
|
73682
|
+
return g.getBoundingBoxBottom() + this.renderer.smuflMetrics.getStemLength(Duration.Quarter, true);
|
|
73355
73683
|
}
|
|
73356
73684
|
}
|
|
73357
73685
|
return 0;
|
|
73358
73686
|
}
|
|
73359
|
-
getLowestNoteY() {
|
|
73360
|
-
return this.noteNumbers ? this.noteNumbers.getLowestNoteY() : 0;
|
|
73687
|
+
getLowestNoteY(requestedPosition) {
|
|
73688
|
+
return this.noteNumbers ? this.noteNumbers.getLowestNoteY(requestedPosition) : 0;
|
|
73361
73689
|
}
|
|
73362
|
-
getHighestNoteY() {
|
|
73363
|
-
return this.noteNumbers ? this.noteNumbers.getHighestNoteY() : 0;
|
|
73690
|
+
getHighestNoteY(requestedPosition) {
|
|
73691
|
+
return this.noteNumbers ? this.noteNumbers.getHighestNoteY(requestedPosition) : 0;
|
|
73364
73692
|
}
|
|
73365
73693
|
buildBoundingsLookup(beatBounds, cx, cy) {
|
|
73366
73694
|
if (this.noteNumbers) {
|
|
@@ -73378,7 +73706,7 @@ class TabBeatGlyph extends BeatOnNoteGlyphBase {
|
|
|
73378
73706
|
if (this.container.beat.slashed && !this.container.beat.notes.some(x => x.isTieDestination)) {
|
|
73379
73707
|
const line = Math.floor((this.renderer.bar.staff.tuning.length - 1) / 2);
|
|
73380
73708
|
const slashY = tabRenderer.getLineY(line);
|
|
73381
|
-
const slashNoteHead = new SlashNoteHeadGlyph(0, slashY, this.container.beat
|
|
73709
|
+
const slashNoteHead = new SlashNoteHeadGlyph(0, slashY, this.container.beat);
|
|
73382
73710
|
slashNoteHead.noteHeadElement = NoteSubElement.GuitarTabFretNumber;
|
|
73383
73711
|
slashNoteHead.effectElement = BeatSubElement.GuitarTabEffects;
|
|
73384
73712
|
this.slash = slashNoteHead;
|
|
@@ -73401,8 +73729,7 @@ class TabBeatGlyph extends BeatOnNoteGlyphBase {
|
|
|
73401
73729
|
//
|
|
73402
73730
|
// Tremolo Picking
|
|
73403
73731
|
if (this.container.beat.isTremolo && !beatEffects.has('tremolo')) {
|
|
73404
|
-
const
|
|
73405
|
-
const glyph = new TremoloPickingGlyph(0, 0, speed);
|
|
73732
|
+
const glyph = new TremoloPickingGlyph(0, 0, this.container.beat.tremoloPicking);
|
|
73406
73733
|
glyph.offsetY = this.renderer.smuflMetrics.glyphTop.get(glyph.symbol);
|
|
73407
73734
|
beatEffects.set('tremolo', glyph);
|
|
73408
73735
|
centeredEffectGlyphs.push(glyph);
|
|
@@ -73411,7 +73738,7 @@ class TabBeatGlyph extends BeatOnNoteGlyphBase {
|
|
|
73411
73738
|
// Note dots
|
|
73412
73739
|
//
|
|
73413
73740
|
if (this.container.beat.dots > 0 && tabRenderer.rhythmMode !== TabRhythmMode.Hidden) {
|
|
73414
|
-
const y =
|
|
73741
|
+
const y = this.getNoteY(this.container.beat.maxNote, NoteYPosition.BottomWithStem);
|
|
73415
73742
|
for (let i = 0; i < this.container.beat.dots; i++) {
|
|
73416
73743
|
this.addEffect(new AugmentationDotGlyph(0, y));
|
|
73417
73744
|
}
|
|
@@ -73473,8 +73800,8 @@ class TabBeatGlyph extends BeatOnNoteGlyphBase {
|
|
|
73473
73800
|
noteNumberGlyph.renderer = this.renderer;
|
|
73474
73801
|
noteNumberGlyph.doLayout();
|
|
73475
73802
|
this.noteNumbers.addNoteGlyph(noteNumberGlyph, n);
|
|
73476
|
-
const topY = noteNumberGlyph.
|
|
73477
|
-
const bottomY =
|
|
73803
|
+
const topY = noteNumberGlyph.getBoundingBoxTop();
|
|
73804
|
+
const bottomY = noteNumberGlyph.getBoundingBoxBottom();
|
|
73478
73805
|
this.renderer.collisionHelper.reserveBeatSlot(this.container.beat, topY, bottomY);
|
|
73479
73806
|
const minString = tr.minString;
|
|
73480
73807
|
const maxString = tr.maxString;
|
|
@@ -74001,30 +74328,6 @@ class TabBarRenderer extends LineBarRenderer {
|
|
|
74001
74328
|
}
|
|
74002
74329
|
}
|
|
74003
74330
|
}
|
|
74004
|
-
adjustSizes() {
|
|
74005
|
-
if (this.rhythmMode !== TabRhythmMode.Hidden) {
|
|
74006
|
-
let shortestTremolo = Duration.Whole;
|
|
74007
|
-
for (const b of this.helpers.beamHelpers) {
|
|
74008
|
-
for (const h of b) {
|
|
74009
|
-
if (h.tremoloDuration && (!shortestTremolo || shortestTremolo < h.tremoloDuration)) {
|
|
74010
|
-
shortestTremolo = h.tremoloDuration;
|
|
74011
|
-
}
|
|
74012
|
-
}
|
|
74013
|
-
}
|
|
74014
|
-
switch (shortestTremolo) {
|
|
74015
|
-
case Duration.Eighth:
|
|
74016
|
-
this.height += this.smuflMetrics.glyphHeights.get(MusicFontSymbol.Tremolo1);
|
|
74017
|
-
break;
|
|
74018
|
-
case Duration.Sixteenth:
|
|
74019
|
-
this.height += this.smuflMetrics.glyphHeights.get(MusicFontSymbol.Tremolo2);
|
|
74020
|
-
break;
|
|
74021
|
-
case Duration.ThirtySecond:
|
|
74022
|
-
this.height += this.smuflMetrics.glyphHeights.get(MusicFontSymbol.Tremolo3);
|
|
74023
|
-
break;
|
|
74024
|
-
}
|
|
74025
|
-
this.registerOverflowBottom(this.settings.notation.rhythmHeight);
|
|
74026
|
-
}
|
|
74027
|
-
}
|
|
74028
74331
|
doLayout() {
|
|
74029
74332
|
const hasStandardNotation = this.bar.staff.showStandardNotation && this.scoreRenderer.layout.profile.has(ScoreBarRenderer.StaffId);
|
|
74030
74333
|
if (!hasStandardNotation) {
|
|
@@ -74105,32 +74408,29 @@ class TabBarRenderer extends LineBarRenderer {
|
|
|
74105
74408
|
drawBeamHelperAsFlags(h) {
|
|
74106
74409
|
return super.drawBeamHelperAsFlags(h) || this.rhythmMode === TabRhythmMode.ShowWithBeams;
|
|
74107
74410
|
}
|
|
74108
|
-
getFlagTopY(beat,
|
|
74109
|
-
const
|
|
74110
|
-
|
|
74111
|
-
|
|
74411
|
+
getFlagTopY(beat, direction) {
|
|
74412
|
+
const maxNote = beat.maxStringNote;
|
|
74413
|
+
const position = direction === BeamDirection.Up ? NoteYPosition.TopWithStem : NoteYPosition.StemDown;
|
|
74414
|
+
if (maxNote) {
|
|
74415
|
+
return this.getNoteY(maxNote, position);
|
|
74416
|
+
}
|
|
74417
|
+
else {
|
|
74418
|
+
return this.getRestY(beat, position);
|
|
74112
74419
|
}
|
|
74113
|
-
return container.getNoteY(beat.minStringNote, NoteYPosition.Bottom) + this.smuflMetrics.staffLineThickness;
|
|
74114
|
-
}
|
|
74115
|
-
getFlagBottomY(_beat, _direction) {
|
|
74116
|
-
return this.getFlagAndBarPos();
|
|
74117
|
-
}
|
|
74118
|
-
getFlagStemSize(_duration, _forceMinStem = false) {
|
|
74119
|
-
return 0; // fixed size via getFlagBottomY
|
|
74120
74420
|
}
|
|
74121
|
-
|
|
74122
|
-
|
|
74421
|
+
getFlagBottomY(beat, direction) {
|
|
74422
|
+
const maxNote = beat.minStringNote;
|
|
74423
|
+
const position = direction === BeamDirection.Up ? NoteYPosition.StemUp : NoteYPosition.BottomWithStem;
|
|
74424
|
+
if (maxNote) {
|
|
74425
|
+
return this.getNoteY(maxNote, position);
|
|
74426
|
+
}
|
|
74427
|
+
else {
|
|
74428
|
+
return this.getRestY(beat, position);
|
|
74429
|
+
}
|
|
74123
74430
|
}
|
|
74124
74431
|
getBeamDirection(_helper) {
|
|
74125
74432
|
return BeamDirection.Down;
|
|
74126
74433
|
}
|
|
74127
|
-
getFlagAndBarPos() {
|
|
74128
|
-
return this.height + this.settings.notation.rhythmHeight - (this._hasTuplets ? this.tupletSize / 2 : 0);
|
|
74129
|
-
}
|
|
74130
|
-
calculateBeamYWithDirection(_h, _x, _direction) {
|
|
74131
|
-
// currently only used for duplets
|
|
74132
|
-
return this.getFlagAndBarPos();
|
|
74133
|
-
}
|
|
74134
74434
|
shouldPaintFlag(beat) {
|
|
74135
74435
|
if (!super.shouldPaintFlag(beat)) {
|
|
74136
74436
|
return false;
|
|
@@ -74153,19 +74453,20 @@ class TabBarRenderer extends LineBarRenderer {
|
|
|
74153
74453
|
holes = this.helpers.collisionHelper.reservedLayoutAreasByDisplayTime.get(beat.displayStart).slots.slice();
|
|
74154
74454
|
holes.sort((a, b) => a.topY - b.topY);
|
|
74155
74455
|
}
|
|
74156
|
-
|
|
74157
|
-
|
|
74158
|
-
|
|
74159
|
-
|
|
74160
|
-
|
|
74161
|
-
|
|
74162
|
-
|
|
74163
|
-
|
|
74164
|
-
|
|
74165
|
-
|
|
74166
|
-
|
|
74167
|
-
|
|
74168
|
-
|
|
74456
|
+
// fast path -> single note == full line
|
|
74457
|
+
if (holes.length === 1) {
|
|
74458
|
+
canvas.fillRect(x, topY, this.smuflMetrics.stemThickness, bottomY - topY);
|
|
74459
|
+
return;
|
|
74460
|
+
}
|
|
74461
|
+
const bottomYRelative = bottomY - cy;
|
|
74462
|
+
// slow path -> multiple notes == lines between notes
|
|
74463
|
+
const bottomHole = holes[holes.length - 1];
|
|
74464
|
+
canvas.fillRect(x, cy + bottomHole.bottomY, this.smuflMetrics.stemThickness, bottomYRelative - bottomHole.bottomY);
|
|
74465
|
+
for (let i = holes.length - 1; i > 0; i--) {
|
|
74466
|
+
const bottomHoleY = holes[i].topY;
|
|
74467
|
+
const topHoleY = holes[i - 1].bottomY;
|
|
74468
|
+
if (topHoleY < bottomHoleY) {
|
|
74469
|
+
canvas.fillRect(x, cy + topHoleY, this.smuflMetrics.stemThickness, bottomHoleY - topHoleY);
|
|
74169
74470
|
}
|
|
74170
74471
|
}
|
|
74171
74472
|
}
|
|
@@ -74173,6 +74474,15 @@ class TabBarRenderer extends LineBarRenderer {
|
|
|
74173
74474
|
_?.[Symbol.dispose]?.();
|
|
74174
74475
|
}
|
|
74175
74476
|
}
|
|
74477
|
+
calculateOverflows(rendererTop, rendererBottom) {
|
|
74478
|
+
super.calculateOverflows(rendererTop, rendererBottom);
|
|
74479
|
+
if (this.bar.isEmpty) {
|
|
74480
|
+
return;
|
|
74481
|
+
}
|
|
74482
|
+
if (this.rhythmMode !== TabRhythmMode.Hidden) {
|
|
74483
|
+
this.calculateBeamingOverflows(rendererTop, rendererBottom);
|
|
74484
|
+
}
|
|
74485
|
+
}
|
|
74176
74486
|
}
|
|
74177
74487
|
|
|
74178
74488
|
/**
|
|
@@ -76350,16 +76660,17 @@ class GpifWriter {
|
|
|
76350
76660
|
beatNode.addElement('Fadding').innerText = FadeType[beat.fade];
|
|
76351
76661
|
}
|
|
76352
76662
|
if (beat.isTremolo) {
|
|
76353
|
-
switch (beat.
|
|
76354
|
-
case
|
|
76663
|
+
switch (beat.tremoloPicking.marks) {
|
|
76664
|
+
case 1:
|
|
76355
76665
|
beatNode.addElement('Tremolo').innerText = '1/2';
|
|
76356
76666
|
break;
|
|
76357
|
-
case
|
|
76667
|
+
case 2:
|
|
76358
76668
|
beatNode.addElement('Tremolo').innerText = '1/4';
|
|
76359
76669
|
break;
|
|
76360
|
-
case
|
|
76670
|
+
case 3:
|
|
76361
76671
|
beatNode.addElement('Tremolo').innerText = '1/8';
|
|
76362
76672
|
break;
|
|
76673
|
+
// NOTE: guitar pro does not support other tremolos
|
|
76363
76674
|
}
|
|
76364
76675
|
}
|
|
76365
76676
|
if (beat.hasChord) {
|
|
@@ -79356,6 +79667,8 @@ const _barrel$2 = /*#__PURE__*/Object.freeze(/*#__PURE__*/Object.defineProperty(
|
|
|
79356
79667
|
get TrackNamePolicy () { return TrackNamePolicy; },
|
|
79357
79668
|
TrackStyle,
|
|
79358
79669
|
get TrackSubElement () { return TrackSubElement; },
|
|
79670
|
+
TremoloPickingEffect,
|
|
79671
|
+
get TremoloPickingStyle () { return TremoloPickingStyle; },
|
|
79359
79672
|
get TripletFeel () { return TripletFeel; },
|
|
79360
79673
|
Tuning,
|
|
79361
79674
|
TupletGroup,
|