@coderline/alphatab 1.8.0-alpha.1660 → 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 +2 -2
package/dist/alphaTab.js
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
|
|
@@ -209,9 +209,9 @@
|
|
|
209
209
|
* @internal
|
|
210
210
|
*/
|
|
211
211
|
class VersionInfo {
|
|
212
|
-
static version = '1.8.0-alpha.
|
|
213
|
-
static date = '
|
|
214
|
-
static commit = '
|
|
212
|
+
static version = '1.8.0-alpha.1667';
|
|
213
|
+
static date = '2026-01-06T02:24:13.312Z';
|
|
214
|
+
static commit = '52bfad1512fe6b0ca977ecefc2e3b5943729385d';
|
|
215
215
|
static print(print) {
|
|
216
216
|
print(`alphaTab ${VersionInfo.version}`);
|
|
217
217
|
print(`commit: ${VersionInfo.commit}`);
|
|
@@ -4646,9 +4646,12 @@
|
|
|
4646
4646
|
MusicFontSymbol[MusicFontSymbol["TextTupletBracketStartLongStem"] = 57857] = "TextTupletBracketStartLongStem";
|
|
4647
4647
|
MusicFontSymbol[MusicFontSymbol["TextTuplet3LongStem"] = 57858] = "TextTuplet3LongStem";
|
|
4648
4648
|
MusicFontSymbol[MusicFontSymbol["TextTupletBracketEndLongStem"] = 57859] = "TextTupletBracketEndLongStem";
|
|
4649
|
-
MusicFontSymbol[MusicFontSymbol["Tremolo3"] = 57890] = "Tremolo3";
|
|
4650
|
-
MusicFontSymbol[MusicFontSymbol["Tremolo2"] = 57889] = "Tremolo2";
|
|
4651
4649
|
MusicFontSymbol[MusicFontSymbol["Tremolo1"] = 57888] = "Tremolo1";
|
|
4650
|
+
MusicFontSymbol[MusicFontSymbol["Tremolo2"] = 57889] = "Tremolo2";
|
|
4651
|
+
MusicFontSymbol[MusicFontSymbol["Tremolo3"] = 57890] = "Tremolo3";
|
|
4652
|
+
MusicFontSymbol[MusicFontSymbol["Tremolo4"] = 57891] = "Tremolo4";
|
|
4653
|
+
MusicFontSymbol[MusicFontSymbol["Tremolo5"] = 57892] = "Tremolo5";
|
|
4654
|
+
MusicFontSymbol[MusicFontSymbol["BuzzRoll"] = 57898] = "BuzzRoll";
|
|
4652
4655
|
MusicFontSymbol[MusicFontSymbol["Flag8thUp"] = 57920] = "Flag8thUp";
|
|
4653
4656
|
MusicFontSymbol[MusicFontSymbol["Flag8thDown"] = 57921] = "Flag8thDown";
|
|
4654
4657
|
MusicFontSymbol[MusicFontSymbol["Flag16thUp"] = 57922] = "Flag16thUp";
|
|
@@ -6955,6 +6958,61 @@
|
|
|
6955
6958
|
Rasgueado[Rasgueado["Peami"] = 18] = "Peami";
|
|
6956
6959
|
})(Rasgueado || (Rasgueado = {}));
|
|
6957
6960
|
|
|
6961
|
+
/**
|
|
6962
|
+
* The style of tremolo affecting mainly the display of the effect.
|
|
6963
|
+
* @public
|
|
6964
|
+
*/
|
|
6965
|
+
var TremoloPickingStyle;
|
|
6966
|
+
(function (TremoloPickingStyle) {
|
|
6967
|
+
/**
|
|
6968
|
+
* A classic tremolo expressed by diagonal bars on the stem.
|
|
6969
|
+
*/
|
|
6970
|
+
TremoloPickingStyle[TremoloPickingStyle["Default"] = 0] = "Default";
|
|
6971
|
+
/**
|
|
6972
|
+
* A buzz roll tremolo expressed by a 'z' shaped symbol.
|
|
6973
|
+
*/
|
|
6974
|
+
TremoloPickingStyle[TremoloPickingStyle["BuzzRoll"] = 1] = "BuzzRoll";
|
|
6975
|
+
})(TremoloPickingStyle || (TremoloPickingStyle = {}));
|
|
6976
|
+
/**
|
|
6977
|
+
* Describes a tremolo picking effect.
|
|
6978
|
+
* @json
|
|
6979
|
+
* @json_strict
|
|
6980
|
+
* @cloneable
|
|
6981
|
+
* @public
|
|
6982
|
+
*/
|
|
6983
|
+
class TremoloPickingEffect {
|
|
6984
|
+
/**
|
|
6985
|
+
* The minimum number of marks for the tremolo picking effect to be valid.
|
|
6986
|
+
*/
|
|
6987
|
+
static minMarks = 0;
|
|
6988
|
+
/**
|
|
6989
|
+
* The max number of marks for the tremolo picking effect to be valid.
|
|
6990
|
+
*/
|
|
6991
|
+
static maxMarks = 5;
|
|
6992
|
+
/**
|
|
6993
|
+
* The number of marks for the tremolo.
|
|
6994
|
+
* A mark is equal to a single bar shown for a default tremolos.
|
|
6995
|
+
*/
|
|
6996
|
+
marks = 0;
|
|
6997
|
+
/**
|
|
6998
|
+
* The style of the tremolo picking.
|
|
6999
|
+
*/
|
|
7000
|
+
style = TremoloPickingStyle.Default;
|
|
7001
|
+
/**
|
|
7002
|
+
* The number of marks define the note value of the note repetition.
|
|
7003
|
+
* e.g. a single mark is an 8th note.
|
|
7004
|
+
*/
|
|
7005
|
+
get duration() {
|
|
7006
|
+
let marks = this.marks;
|
|
7007
|
+
if (marks < 1) {
|
|
7008
|
+
marks = 1;
|
|
7009
|
+
}
|
|
7010
|
+
const baseDuration = Duration.Eighth;
|
|
7011
|
+
const actualDuration = baseDuration * Math.pow(2, marks);
|
|
7012
|
+
return actualDuration;
|
|
7013
|
+
}
|
|
7014
|
+
}
|
|
7015
|
+
|
|
6958
7016
|
/**
|
|
6959
7017
|
* Lists the different modes on how beaming for a beat should be done.
|
|
6960
7018
|
* @public
|
|
@@ -7377,13 +7435,59 @@
|
|
|
7377
7435
|
* Gets or sets the pickstroke applied on this beat.
|
|
7378
7436
|
*/
|
|
7379
7437
|
pickStroke = PickStroke.None;
|
|
7438
|
+
/**
|
|
7439
|
+
* Whether this beat has a tremolo picking effect.
|
|
7440
|
+
*/
|
|
7380
7441
|
get isTremolo() {
|
|
7381
|
-
return
|
|
7442
|
+
return this.tremoloPicking !== undefined;
|
|
7443
|
+
}
|
|
7444
|
+
/**
|
|
7445
|
+
* The tremolo picking effect.
|
|
7446
|
+
*/
|
|
7447
|
+
tremoloPicking;
|
|
7448
|
+
/**
|
|
7449
|
+
* The speed of the tremolo.
|
|
7450
|
+
* @deprecated Set {@link tremoloPicking} instead.
|
|
7451
|
+
*/
|
|
7452
|
+
get tremoloSpeed() {
|
|
7453
|
+
const tremolo = this.tremoloPicking;
|
|
7454
|
+
if (tremolo) {
|
|
7455
|
+
return tremolo.duration;
|
|
7456
|
+
}
|
|
7457
|
+
return null;
|
|
7382
7458
|
}
|
|
7383
7459
|
/**
|
|
7384
|
-
*
|
|
7460
|
+
* The speed of the tremolo.
|
|
7461
|
+
* @deprecated Set {@link tremoloPicking} instead.
|
|
7385
7462
|
*/
|
|
7386
|
-
tremoloSpeed
|
|
7463
|
+
set tremoloSpeed(value) {
|
|
7464
|
+
if (value === null) {
|
|
7465
|
+
this.tremoloPicking = undefined;
|
|
7466
|
+
return;
|
|
7467
|
+
}
|
|
7468
|
+
let effect = this.tremoloPicking;
|
|
7469
|
+
if (effect === undefined) {
|
|
7470
|
+
effect = new TremoloPickingEffect();
|
|
7471
|
+
this.tremoloPicking = effect;
|
|
7472
|
+
}
|
|
7473
|
+
switch (value) {
|
|
7474
|
+
case Duration.Eighth:
|
|
7475
|
+
effect.marks = 1;
|
|
7476
|
+
break;
|
|
7477
|
+
case Duration.Sixteenth:
|
|
7478
|
+
effect.marks = 2;
|
|
7479
|
+
break;
|
|
7480
|
+
case Duration.ThirtySecond:
|
|
7481
|
+
effect.marks = 3;
|
|
7482
|
+
break;
|
|
7483
|
+
case Duration.SixtyFourth:
|
|
7484
|
+
effect.marks = 4;
|
|
7485
|
+
break;
|
|
7486
|
+
case Duration.OneHundredTwentyEighth:
|
|
7487
|
+
effect.marks = 5;
|
|
7488
|
+
break;
|
|
7489
|
+
}
|
|
7490
|
+
}
|
|
7387
7491
|
/**
|
|
7388
7492
|
* Gets or sets whether a crescendo/decrescendo is applied on this beat.
|
|
7389
7493
|
*/
|
|
@@ -7678,6 +7782,12 @@
|
|
|
7678
7782
|
if (this.brushType === BrushType.None) {
|
|
7679
7783
|
this.brushDuration = 0;
|
|
7680
7784
|
}
|
|
7785
|
+
const tremolo = this.tremoloPicking;
|
|
7786
|
+
if (tremolo !== undefined) {
|
|
7787
|
+
if (tremolo.marks < TremoloPickingEffect.minMarks || tremolo.marks > TremoloPickingEffect.maxMarks) {
|
|
7788
|
+
this.tremoloPicking = undefined;
|
|
7789
|
+
}
|
|
7790
|
+
}
|
|
7681
7791
|
const displayMode = !settings ? exports.NotationMode.GuitarPro : settings.notation.notationMode;
|
|
7682
7792
|
let isGradual = this.text === 'grad' || this.text === 'grad.';
|
|
7683
7793
|
if (isGradual && displayMode === exports.NotationMode.SongBook) {
|
|
@@ -8086,6 +8196,23 @@
|
|
|
8086
8196
|
}
|
|
8087
8197
|
}
|
|
8088
8198
|
|
|
8199
|
+
// <auto-generated>
|
|
8200
|
+
// This code was auto-generated.
|
|
8201
|
+
// Changes to this file may cause incorrect behavior and will be lost if
|
|
8202
|
+
// the code is regenerated.
|
|
8203
|
+
// </auto-generated>
|
|
8204
|
+
/**
|
|
8205
|
+
* @internal
|
|
8206
|
+
*/
|
|
8207
|
+
class TremoloPickingEffectCloner {
|
|
8208
|
+
static clone(original) {
|
|
8209
|
+
const clone = new TremoloPickingEffect();
|
|
8210
|
+
clone.marks = original.marks;
|
|
8211
|
+
clone.style = original.style;
|
|
8212
|
+
return clone;
|
|
8213
|
+
}
|
|
8214
|
+
}
|
|
8215
|
+
|
|
8089
8216
|
// <auto-generated>
|
|
8090
8217
|
// This code was auto-generated.
|
|
8091
8218
|
// Changes to this file may cause incorrect behavior and will be lost if
|
|
@@ -8138,7 +8265,7 @@
|
|
|
8138
8265
|
clone.chordId = original.chordId;
|
|
8139
8266
|
clone.graceType = original.graceType;
|
|
8140
8267
|
clone.pickStroke = original.pickStroke;
|
|
8141
|
-
clone.
|
|
8268
|
+
clone.tremoloPicking = original.tremoloPicking ? TremoloPickingEffectCloner.clone(original.tremoloPicking) : undefined;
|
|
8142
8269
|
clone.crescendo = original.crescendo;
|
|
8143
8270
|
clone.displayStart = original.displayStart;
|
|
8144
8271
|
clone.playbackStart = original.playbackStart;
|
|
@@ -8521,6 +8648,11 @@
|
|
|
8521
8648
|
['dadoublecoda', 18]
|
|
8522
8649
|
]);
|
|
8523
8650
|
static directionReversed = AlphaTex1EnumMappings._reverse(AlphaTex1EnumMappings.direction);
|
|
8651
|
+
static tremoloPickingStyle = new Map([
|
|
8652
|
+
['default', 0],
|
|
8653
|
+
['buzzroll', 1]
|
|
8654
|
+
]);
|
|
8655
|
+
static tremoloPickingStyleReversed = AlphaTex1EnumMappings._reverse(AlphaTex1EnumMappings.tremoloPickingStyle);
|
|
8524
8656
|
static keySignaturesMinorReversed = new Map([
|
|
8525
8657
|
[-7, 'abminor'],
|
|
8526
8658
|
[-6, 'ebminor'],
|
|
@@ -9281,7 +9413,15 @@
|
|
|
9281
9413
|
],
|
|
9282
9414
|
['volume', [[[[16], 0]]]],
|
|
9283
9415
|
['balance', [[[[16], 0]]]],
|
|
9284
|
-
[
|
|
9416
|
+
[
|
|
9417
|
+
'tp',
|
|
9418
|
+
[
|
|
9419
|
+
[
|
|
9420
|
+
[[16], 0],
|
|
9421
|
+
[[10, 17], 1, ['default', 'buzzroll']]
|
|
9422
|
+
]
|
|
9423
|
+
]
|
|
9424
|
+
],
|
|
9285
9425
|
[
|
|
9286
9426
|
'barre',
|
|
9287
9427
|
[
|
|
@@ -15199,28 +15339,45 @@
|
|
|
15199
15339
|
beat.automations.push(balanceAutomation);
|
|
15200
15340
|
return ApplyNodeResult.Applied;
|
|
15201
15341
|
case 'tp':
|
|
15202
|
-
|
|
15342
|
+
const tremolo = new TremoloPickingEffect();
|
|
15343
|
+
beat.tremoloPicking = tremolo;
|
|
15203
15344
|
if (p.arguments && p.arguments.arguments.length > 0) {
|
|
15204
|
-
|
|
15205
|
-
|
|
15206
|
-
|
|
15207
|
-
|
|
15208
|
-
|
|
15209
|
-
|
|
15210
|
-
|
|
15211
|
-
|
|
15212
|
-
|
|
15213
|
-
|
|
15214
|
-
|
|
15215
|
-
|
|
15216
|
-
|
|
15217
|
-
|
|
15218
|
-
|
|
15219
|
-
|
|
15220
|
-
|
|
15221
|
-
|
|
15222
|
-
|
|
15345
|
+
if (p.arguments.arguments.length > 0) {
|
|
15346
|
+
const tremoloMarks = p.arguments.arguments[0].value;
|
|
15347
|
+
if (tremoloMarks >= TremoloPickingEffect.minMarks &&
|
|
15348
|
+
tremoloMarks <= TremoloPickingEffect.maxMarks) {
|
|
15349
|
+
tremolo.marks = tremoloMarks;
|
|
15350
|
+
}
|
|
15351
|
+
else {
|
|
15352
|
+
switch (tremoloMarks) {
|
|
15353
|
+
// backwards compatibility
|
|
15354
|
+
case 8:
|
|
15355
|
+
tremolo.marks = 1;
|
|
15356
|
+
break;
|
|
15357
|
+
case 16:
|
|
15358
|
+
tremolo.marks = 2;
|
|
15359
|
+
break;
|
|
15360
|
+
case 32:
|
|
15361
|
+
tremolo.marks = 3;
|
|
15362
|
+
break;
|
|
15363
|
+
default:
|
|
15364
|
+
importer.addSemanticDiagnostic({
|
|
15365
|
+
code: AlphaTexDiagnosticCode.AT209,
|
|
15366
|
+
message: `Unexpected tremolo marks value '${tremoloMarks}, expected: ${TremoloPickingEffect.minMarks}-${TremoloPickingEffect.maxMarks}, or legacy: 8, 16 or 32`,
|
|
15367
|
+
severity: AlphaTexDiagnosticsSeverity.Error,
|
|
15368
|
+
start: p.arguments.arguments[0].start,
|
|
15369
|
+
end: p.arguments.arguments[0].end
|
|
15370
|
+
});
|
|
15371
|
+
return ApplyNodeResult.NotAppliedSemanticError;
|
|
15372
|
+
}
|
|
15373
|
+
}
|
|
15374
|
+
}
|
|
15375
|
+
if (p.arguments.arguments.length > 1) {
|
|
15376
|
+
const tremoloStyle = AlphaTex1LanguageHandler._parseEnumValue(importer, p.arguments, 'tremolo picking style', AlphaTex1EnumMappings.tremoloPickingStyle, 1);
|
|
15377
|
+
if (tremoloStyle === undefined) {
|
|
15223
15378
|
return ApplyNodeResult.NotAppliedSemanticError;
|
|
15379
|
+
}
|
|
15380
|
+
tremolo.style = tremoloStyle;
|
|
15224
15381
|
}
|
|
15225
15382
|
}
|
|
15226
15383
|
return ApplyNodeResult.Applied;
|
|
@@ -16427,7 +16584,11 @@
|
|
|
16427
16584
|
: Atnf.identValue(AlphaTex1EnumMappings.graceTypeReversed.get(beat.graceType)));
|
|
16428
16585
|
}
|
|
16429
16586
|
if (beat.isTremolo) {
|
|
16430
|
-
|
|
16587
|
+
const values = [Atnf.number(beat.tremoloPicking.marks)];
|
|
16588
|
+
if (beat.tremoloPicking.style !== TremoloPickingStyle.Default) {
|
|
16589
|
+
values.push(Atnf.ident(TremoloPickingStyle[beat.tremoloPicking.style]));
|
|
16590
|
+
}
|
|
16591
|
+
Atnf.prop(properties, 'tp', Atnf.args(values));
|
|
16431
16592
|
}
|
|
16432
16593
|
switch (beat.crescendo) {
|
|
16433
16594
|
case CrescendoType.Crescendo:
|
|
@@ -16828,9 +16989,6 @@
|
|
|
16828
16989
|
// even start translating when we have parser errors
|
|
16829
16990
|
// as long we have some nodes, we can already start semantically
|
|
16830
16991
|
// validating and using them
|
|
16831
|
-
if (scoreNode.bars.length === 0) {
|
|
16832
|
-
throw new UnsupportedFormatError('No alphaTex data found');
|
|
16833
|
-
}
|
|
16834
16992
|
this._bars(scoreNode);
|
|
16835
16993
|
if (this.semanticDiagnostics.hasErrors) {
|
|
16836
16994
|
if (this._state.hasAnyProperData) {
|
|
@@ -21451,18 +21609,9 @@
|
|
|
21451
21609
|
graceBeat.addNote(graceNote);
|
|
21452
21610
|
}
|
|
21453
21611
|
readTremoloPicking(beat) {
|
|
21454
|
-
const
|
|
21455
|
-
|
|
21456
|
-
|
|
21457
|
-
beat.tremoloSpeed = Duration.Eighth;
|
|
21458
|
-
break;
|
|
21459
|
-
case 2:
|
|
21460
|
-
beat.tremoloSpeed = Duration.Sixteenth;
|
|
21461
|
-
break;
|
|
21462
|
-
case 3:
|
|
21463
|
-
beat.tremoloSpeed = Duration.ThirtySecond;
|
|
21464
|
-
break;
|
|
21465
|
-
}
|
|
21612
|
+
const effect = new TremoloPickingEffect();
|
|
21613
|
+
beat.tremoloPicking = effect;
|
|
21614
|
+
effect.marks = this.data.readByte();
|
|
21466
21615
|
}
|
|
21467
21616
|
readSlide(note) {
|
|
21468
21617
|
if (this._versionNumber >= 500) {
|
|
@@ -23709,15 +23858,17 @@
|
|
|
23709
23858
|
}
|
|
23710
23859
|
break;
|
|
23711
23860
|
case 'Tremolo':
|
|
23861
|
+
const tremolo = new TremoloPickingEffect();
|
|
23862
|
+
beat.tremoloPicking = tremolo;
|
|
23712
23863
|
switch (c.innerText) {
|
|
23713
23864
|
case '1/2':
|
|
23714
|
-
|
|
23865
|
+
tremolo.marks = 1;
|
|
23715
23866
|
break;
|
|
23716
23867
|
case '1/4':
|
|
23717
|
-
|
|
23868
|
+
tremolo.marks = 2;
|
|
23718
23869
|
break;
|
|
23719
23870
|
case '1/8':
|
|
23720
|
-
|
|
23871
|
+
tremolo.marks = 3;
|
|
23721
23872
|
break;
|
|
23722
23873
|
}
|
|
23723
23874
|
break;
|
|
@@ -28785,16 +28936,12 @@
|
|
|
28785
28936
|
break;
|
|
28786
28937
|
// case 'schleifer': Not supported
|
|
28787
28938
|
case 'tremolo':
|
|
28788
|
-
|
|
28789
|
-
|
|
28790
|
-
|
|
28791
|
-
|
|
28792
|
-
|
|
28793
|
-
|
|
28794
|
-
break;
|
|
28795
|
-
case '3':
|
|
28796
|
-
note.beat.tremoloSpeed = Duration.ThirtySecond;
|
|
28797
|
-
break;
|
|
28939
|
+
const tremolo = new TremoloPickingEffect();
|
|
28940
|
+
note.beat.tremoloPicking = tremolo;
|
|
28941
|
+
tremolo.marks = Number.parseInt(c.innerText, 10);
|
|
28942
|
+
if ((c.getAttribute('type', '') === 'unmeasured' && tremolo.marks === 0) ||
|
|
28943
|
+
c.getAttribute('smufl', '') === 'buzzRoll') {
|
|
28944
|
+
tremolo.style = TremoloPickingStyle.BuzzRoll;
|
|
28798
28945
|
}
|
|
28799
28946
|
break;
|
|
28800
28947
|
// case 'haydn': Not supported
|
|
@@ -37905,6 +38052,38 @@
|
|
|
37905
38052
|
}
|
|
37906
38053
|
}
|
|
37907
38054
|
|
|
38055
|
+
/**
|
|
38056
|
+
* @internal
|
|
38057
|
+
*/
|
|
38058
|
+
class TremoloPickingEffectSerializer {
|
|
38059
|
+
static fromJson(obj, m) {
|
|
38060
|
+
if (!m) {
|
|
38061
|
+
return;
|
|
38062
|
+
}
|
|
38063
|
+
JsonHelper.forEach(m, (v, k) => TremoloPickingEffectSerializer.setProperty(obj, k, v));
|
|
38064
|
+
}
|
|
38065
|
+
static toJson(obj) {
|
|
38066
|
+
if (!obj) {
|
|
38067
|
+
return null;
|
|
38068
|
+
}
|
|
38069
|
+
const o = new Map();
|
|
38070
|
+
o.set("marks", obj.marks);
|
|
38071
|
+
o.set("style", obj.style);
|
|
38072
|
+
return o;
|
|
38073
|
+
}
|
|
38074
|
+
static setProperty(obj, property, v) {
|
|
38075
|
+
switch (property) {
|
|
38076
|
+
case "marks":
|
|
38077
|
+
obj.marks = v;
|
|
38078
|
+
return true;
|
|
38079
|
+
case "style":
|
|
38080
|
+
obj.style = JsonHelper.parseEnum(v, TremoloPickingStyle);
|
|
38081
|
+
return true;
|
|
38082
|
+
}
|
|
38083
|
+
return false;
|
|
38084
|
+
}
|
|
38085
|
+
}
|
|
38086
|
+
|
|
37908
38087
|
/**
|
|
37909
38088
|
* @internal
|
|
37910
38089
|
*/
|
|
@@ -37987,7 +38166,9 @@
|
|
|
37987
38166
|
o.set("chordid", obj.chordId);
|
|
37988
38167
|
o.set("gracetype", obj.graceType);
|
|
37989
38168
|
o.set("pickstroke", obj.pickStroke);
|
|
37990
|
-
|
|
38169
|
+
if (obj.tremoloPicking) {
|
|
38170
|
+
o.set("tremolopicking", TremoloPickingEffectSerializer.toJson(obj.tremoloPicking));
|
|
38171
|
+
}
|
|
37991
38172
|
o.set("crescendo", obj.crescendo);
|
|
37992
38173
|
o.set("displaystart", obj.displayStart);
|
|
37993
38174
|
o.set("playbackstart", obj.playbackStart);
|
|
@@ -38113,8 +38294,14 @@
|
|
|
38113
38294
|
case "pickstroke":
|
|
38114
38295
|
obj.pickStroke = JsonHelper.parseEnum(v, PickStroke);
|
|
38115
38296
|
return true;
|
|
38116
|
-
case "
|
|
38117
|
-
|
|
38297
|
+
case "tremolopicking":
|
|
38298
|
+
if (v) {
|
|
38299
|
+
obj.tremoloPicking = new TremoloPickingEffect();
|
|
38300
|
+
TremoloPickingEffectSerializer.fromJson(obj.tremoloPicking, v);
|
|
38301
|
+
}
|
|
38302
|
+
else {
|
|
38303
|
+
obj.tremoloPicking = undefined;
|
|
38304
|
+
}
|
|
38118
38305
|
return true;
|
|
38119
38306
|
case "crescendo":
|
|
38120
38307
|
obj.crescendo = JsonHelper.parseEnum(v, CrescendoType);
|
|
@@ -39428,6 +39615,7 @@
|
|
|
39428
39615
|
clone.tuningGlyphStringRowPadding = original.tuningGlyphStringRowPadding;
|
|
39429
39616
|
clone.directionsScale = original.directionsScale;
|
|
39430
39617
|
clone.multiVoiceDisplacedNoteHeadSpacing = original.multiVoiceDisplacedNoteHeadSpacing;
|
|
39618
|
+
clone.stemFlagHeight = new Map(original.stemFlagHeight);
|
|
39431
39619
|
return clone;
|
|
39432
39620
|
}
|
|
39433
39621
|
}
|
|
@@ -39739,6 +39927,20 @@
|
|
|
39739
39927
|
this.stemFlagOffsets.set(Duration.SixtyFourth, 0);
|
|
39740
39928
|
this.stemFlagOffsets.set(Duration.OneHundredTwentyEighth, 0);
|
|
39741
39929
|
this.stemFlagOffsets.set(Duration.TwoHundredFiftySixth, 0);
|
|
39930
|
+
// Workaround for: https://github.com/w3c/smufl/issues/203
|
|
39931
|
+
// There is no clear anchor for the height of flags on the stem side yet.
|
|
39932
|
+
// These aproximations are tested with bravura
|
|
39933
|
+
this.stemFlagHeight.set(Duration.QuadrupleWhole, 0);
|
|
39934
|
+
this.stemFlagHeight.set(Duration.DoubleWhole, 0);
|
|
39935
|
+
this.stemFlagHeight.set(Duration.Whole, 0);
|
|
39936
|
+
this.stemFlagHeight.set(Duration.Half, 0);
|
|
39937
|
+
this.stemFlagHeight.set(Duration.Quarter, 0);
|
|
39938
|
+
this.stemFlagHeight.set(Duration.Eighth, 1 * this.oneStaffSpace);
|
|
39939
|
+
this.stemFlagHeight.set(Duration.Sixteenth, 1.5 * this.oneStaffSpace);
|
|
39940
|
+
this.stemFlagHeight.set(Duration.ThirtySecond, 2 * this.oneStaffSpace);
|
|
39941
|
+
this.stemFlagHeight.set(Duration.SixtyFourth, 3 * this.oneStaffSpace);
|
|
39942
|
+
this.stemFlagHeight.set(Duration.OneHundredTwentyEighth, 3.5 * this.oneStaffSpace);
|
|
39943
|
+
this.stemFlagHeight.set(Duration.TwoHundredFiftySixth, 4.2 * this.oneStaffSpace);
|
|
39742
39944
|
for (const [g, v] of Object.entries(smufl.glyphsWithAnchors)) {
|
|
39743
39945
|
const symbol = EngravingSettings._smuflNameToMusicFontSymbol(g);
|
|
39744
39946
|
if (symbol) {
|
|
@@ -40085,6 +40287,19 @@
|
|
|
40085
40287
|
* in case of multi-voice note head overlaps.
|
|
40086
40288
|
*/
|
|
40087
40289
|
multiVoiceDisplacedNoteHeadSpacing = 0;
|
|
40290
|
+
/**
|
|
40291
|
+
* Calculates the stem height for a note of the given duration.
|
|
40292
|
+
* @param duration The duration to calculate the height respecting flag sizes.
|
|
40293
|
+
* @param hasFlag True if we need to respect flags, false if we have beams.
|
|
40294
|
+
* @returns The total stem height
|
|
40295
|
+
*/
|
|
40296
|
+
getStemLength(duration, hasFlag) {
|
|
40297
|
+
return this.standardStemLength + (hasFlag ? this.stemFlagOffsets.get(duration) : 0);
|
|
40298
|
+
}
|
|
40299
|
+
/**
|
|
40300
|
+
* The space needed by flags on the stem-side from top to bottom to place.
|
|
40301
|
+
*/
|
|
40302
|
+
stemFlagHeight = new Map();
|
|
40088
40303
|
// Idea: maybe we can encode and pack this large metadata into a more compact format (e.g. BSON or a custom binary blob?)
|
|
40089
40304
|
// This metadata below is updated automatically from the bravura_metadata.json via npm script
|
|
40090
40305
|
static bravuraMetadata =
|
|
@@ -40217,6 +40432,10 @@
|
|
|
40217
40432
|
bBoxNE: [1.876, 1.18],
|
|
40218
40433
|
bBoxSW: [0, 0]
|
|
40219
40434
|
},
|
|
40435
|
+
buzzRoll: {
|
|
40436
|
+
bBoxNE: [0.624, 0.464],
|
|
40437
|
+
bBoxSW: [-0.62, -0.464]
|
|
40438
|
+
},
|
|
40220
40439
|
cClef: {
|
|
40221
40440
|
bBoxNE: [2.796, 2.024],
|
|
40222
40441
|
bBoxSW: [0, -2.024]
|
|
@@ -41173,6 +41392,14 @@
|
|
|
41173
41392
|
bBoxNE: [0.6, 1.112],
|
|
41174
41393
|
bBoxSW: [-0.6, -1.12]
|
|
41175
41394
|
},
|
|
41395
|
+
tremolo4: {
|
|
41396
|
+
bBoxNE: [0.6, 1.496],
|
|
41397
|
+
bBoxSW: [-0.6, -1.48]
|
|
41398
|
+
},
|
|
41399
|
+
tremolo5: {
|
|
41400
|
+
bBoxNE: [0.6, 1.88],
|
|
41401
|
+
bBoxSW: [-0.604, -1.84]
|
|
41402
|
+
},
|
|
41176
41403
|
tuplet0: {
|
|
41177
41404
|
bBoxNE: [1.2731041262817027, 1.5],
|
|
41178
41405
|
bBoxSW: [-0.001204330173715796, -0.032]
|
|
@@ -41820,6 +42047,13 @@
|
|
|
41820
42047
|
o.set("tuningglyphstringrowpadding", obj.tuningGlyphStringRowPadding);
|
|
41821
42048
|
o.set("directionsscale", obj.directionsScale);
|
|
41822
42049
|
o.set("multivoicedisplacednoteheadspacing", obj.multiVoiceDisplacedNoteHeadSpacing);
|
|
42050
|
+
{
|
|
42051
|
+
const m = new Map();
|
|
42052
|
+
o.set("stemflagheight", m);
|
|
42053
|
+
for (const [k, v] of obj.stemFlagHeight) {
|
|
42054
|
+
m.set(k.toString(), v);
|
|
42055
|
+
}
|
|
42056
|
+
}
|
|
41823
42057
|
return o;
|
|
41824
42058
|
}
|
|
41825
42059
|
static setProperty(obj, property, v) {
|
|
@@ -42101,6 +42335,12 @@
|
|
|
42101
42335
|
case "multivoicedisplacednoteheadspacing":
|
|
42102
42336
|
obj.multiVoiceDisplacedNoteHeadSpacing = v;
|
|
42103
42337
|
return true;
|
|
42338
|
+
case "stemflagheight":
|
|
42339
|
+
obj.stemFlagHeight = new Map();
|
|
42340
|
+
JsonHelper.forEach(v, (v, k) => {
|
|
42341
|
+
obj.stemFlagHeight.set(JsonHelper.parseEnum(k, Duration), v);
|
|
42342
|
+
});
|
|
42343
|
+
return true;
|
|
42104
42344
|
}
|
|
42105
42345
|
return false;
|
|
42106
42346
|
}
|
|
@@ -48322,7 +48562,12 @@
|
|
|
48322
48562
|
}
|
|
48323
48563
|
_generateTremoloPicking(note, noteStart, noteDuration, noteKey, dynamicValue, channel) {
|
|
48324
48564
|
const track = note.beat.voice.bar.staff.track;
|
|
48325
|
-
|
|
48565
|
+
const marks = note.beat.tremoloPicking.marks;
|
|
48566
|
+
if (marks === 0) {
|
|
48567
|
+
return;
|
|
48568
|
+
}
|
|
48569
|
+
// the marks represent the duration
|
|
48570
|
+
let tpLength = MidiUtils.toTicks(note.beat.tremoloPicking.duration);
|
|
48326
48571
|
let tick = noteStart;
|
|
48327
48572
|
const end = noteStart + noteDuration.untilTieOrSlideEnd;
|
|
48328
48573
|
while (tick + 10 < end) {
|
|
@@ -48748,6 +48993,12 @@
|
|
|
48748
48993
|
beat;
|
|
48749
48994
|
preNotes;
|
|
48750
48995
|
onNotes;
|
|
48996
|
+
getLowestNoteY(requestedPosition) {
|
|
48997
|
+
return this.onNotes.getLowestNoteY(requestedPosition);
|
|
48998
|
+
}
|
|
48999
|
+
getHighestNoteY(requestedPosition) {
|
|
49000
|
+
return this.onNotes.getHighestNoteY(requestedPosition);
|
|
49001
|
+
}
|
|
48751
49002
|
get beatId() {
|
|
48752
49003
|
return this.beat.id;
|
|
48753
49004
|
}
|
|
@@ -48811,7 +49062,7 @@
|
|
|
48811
49062
|
return helper.hasFlag(false, undefined);
|
|
48812
49063
|
}
|
|
48813
49064
|
get postBeatStretch() {
|
|
48814
|
-
return
|
|
49065
|
+
return this.onNotes.computedWidth + this._tieWidth - this.onNotes.onTimeX;
|
|
48815
49066
|
}
|
|
48816
49067
|
registerLayoutingInfo(layoutings) {
|
|
48817
49068
|
const preBeatStretch = this.preNotes.computedWidth + this.onNotes.onTimeX;
|
|
@@ -60021,16 +60272,22 @@
|
|
|
60021
60272
|
return false;
|
|
60022
60273
|
}
|
|
60023
60274
|
let y = 0;
|
|
60275
|
+
// TODO. activate padding
|
|
60276
|
+
// const paddingTop = this._isTopContainer ? 0 : this._renderer.settings.display.effectBandPaddingBottom;
|
|
60277
|
+
// const paddingBottom = this._isTopContainer ? this._renderer.settings.display.effectBandPaddingBottom : 0;
|
|
60278
|
+
const paddingTop = 0;
|
|
60279
|
+
const paddingBottom = this._renderer.settings.display.effectBandPaddingBottom;
|
|
60024
60280
|
for (const slot of this._effectBandSizingInfo.slots) {
|
|
60025
60281
|
slot.shared.y = y;
|
|
60026
60282
|
for (const band of slot.bands) {
|
|
60283
|
+
y += paddingTop;
|
|
60027
60284
|
band.y = y;
|
|
60028
60285
|
if (finalize) {
|
|
60029
60286
|
band.finalizeBand();
|
|
60030
60287
|
}
|
|
60031
60288
|
band.height = slot.shared.height;
|
|
60032
60289
|
}
|
|
60033
|
-
y += slot.shared.height +
|
|
60290
|
+
y += slot.shared.height + paddingBottom;
|
|
60034
60291
|
}
|
|
60035
60292
|
y = Math.ceil(y);
|
|
60036
60293
|
if (y !== this.height) {
|
|
@@ -60260,6 +60517,20 @@
|
|
|
60260
60517
|
}
|
|
60261
60518
|
return 0;
|
|
60262
60519
|
}
|
|
60520
|
+
getLowestNoteY(beat, position) {
|
|
60521
|
+
const container = this.getBeatContainer(beat);
|
|
60522
|
+
if (container) {
|
|
60523
|
+
return container.y + container.getLowestNoteY(position);
|
|
60524
|
+
}
|
|
60525
|
+
return 0;
|
|
60526
|
+
}
|
|
60527
|
+
getHighestNoteY(beat, position) {
|
|
60528
|
+
const container = this.getBeatContainer(beat);
|
|
60529
|
+
if (container) {
|
|
60530
|
+
return container.y + container.getHighestNoteY(position);
|
|
60531
|
+
}
|
|
60532
|
+
return 0;
|
|
60533
|
+
}
|
|
60263
60534
|
getNoteX(note, requestedPosition) {
|
|
60264
60535
|
const container = this.getBeatContainer(note.beat);
|
|
60265
60536
|
if (container) {
|
|
@@ -60272,14 +60543,14 @@
|
|
|
60272
60543
|
if (beat) {
|
|
60273
60544
|
return beat.y + beat.getNoteY(note, requestedPosition);
|
|
60274
60545
|
}
|
|
60275
|
-
return
|
|
60546
|
+
return 0;
|
|
60276
60547
|
}
|
|
60277
60548
|
getRestY(beat, requestedPosition) {
|
|
60278
60549
|
const container = this.getBeatContainer(beat);
|
|
60279
60550
|
if (container) {
|
|
60280
60551
|
return container.y + container.getRestY(requestedPosition);
|
|
60281
60552
|
}
|
|
60282
|
-
return
|
|
60553
|
+
return 0;
|
|
60283
60554
|
}
|
|
60284
60555
|
getBeatContainer(beat) {
|
|
60285
60556
|
if (!this._beatGlyphLookup.has(beat.id)) {
|
|
@@ -60949,16 +61220,18 @@
|
|
|
60949
61220
|
const g = this._glyph;
|
|
60950
61221
|
if (g) {
|
|
60951
61222
|
switch (requestedPosition) {
|
|
60952
|
-
case NoteYPosition.TopWithStem:
|
|
60953
61223
|
case NoteYPosition.Top:
|
|
60954
61224
|
return g.y;
|
|
61225
|
+
case NoteYPosition.TopWithStem:
|
|
61226
|
+
return g.y - this.renderer.smuflMetrics.getStemLength(Duration.Quarter, true);
|
|
60955
61227
|
case NoteYPosition.Center:
|
|
60956
61228
|
case NoteYPosition.StemUp:
|
|
60957
61229
|
case NoteYPosition.StemDown:
|
|
60958
61230
|
return g.y + g.height / 2;
|
|
60959
61231
|
case NoteYPosition.Bottom:
|
|
60960
|
-
case NoteYPosition.BottomWithStem:
|
|
60961
61232
|
return g.y + g.height;
|
|
61233
|
+
case NoteYPosition.BottomWithStem:
|
|
61234
|
+
return g.y + g.height + this.renderer.smuflMetrics.getStemLength(Duration.Quarter, true);
|
|
60962
61235
|
}
|
|
60963
61236
|
}
|
|
60964
61237
|
return 0;
|
|
@@ -60966,6 +61239,12 @@
|
|
|
60966
61239
|
getNoteY(_note, requestedPosition) {
|
|
60967
61240
|
return this.getRestY(requestedPosition);
|
|
60968
61241
|
}
|
|
61242
|
+
getHighestNoteY(position) {
|
|
61243
|
+
return this.getRestY(position);
|
|
61244
|
+
}
|
|
61245
|
+
getLowestNoteY(position) {
|
|
61246
|
+
return this.getRestY(position);
|
|
61247
|
+
}
|
|
60969
61248
|
getNoteX(_note, requestedPosition) {
|
|
60970
61249
|
const g = this._glyph;
|
|
60971
61250
|
if (g) {
|
|
@@ -61060,7 +61339,6 @@
|
|
|
61060
61339
|
voice = null;
|
|
61061
61340
|
beats = [];
|
|
61062
61341
|
shortestDuration = Duration.QuadrupleWhole;
|
|
61063
|
-
tremoloDuration;
|
|
61064
61342
|
/**
|
|
61065
61343
|
* an indicator whether any beat has a tuplet on it.
|
|
61066
61344
|
*/
|
|
@@ -61103,43 +61381,9 @@
|
|
|
61103
61381
|
this.drawingInfos.clear();
|
|
61104
61382
|
}
|
|
61105
61383
|
}
|
|
61106
|
-
direction = BeamDirection.Up;
|
|
61107
61384
|
finish() {
|
|
61108
|
-
this.direction = this._calculateDirection();
|
|
61109
61385
|
this._renderer.completeBeamingHelper(this);
|
|
61110
61386
|
}
|
|
61111
|
-
_calculateDirection() {
|
|
61112
|
-
// no proper voice (should not happen usually)
|
|
61113
|
-
if (!this.voice) {
|
|
61114
|
-
return BeamDirection.Up;
|
|
61115
|
-
}
|
|
61116
|
-
// we have a preferred direction
|
|
61117
|
-
if (this.preferredBeamDirection !== null) {
|
|
61118
|
-
return this.preferredBeamDirection;
|
|
61119
|
-
}
|
|
61120
|
-
// on multi-voice setups secondary voices are always down
|
|
61121
|
-
if (this.voice.index > 0) {
|
|
61122
|
-
return this._invert(BeamDirection.Down);
|
|
61123
|
-
}
|
|
61124
|
-
// on multi-voice setups primary voices are always up
|
|
61125
|
-
if (this.voice.bar.isMultiVoice) {
|
|
61126
|
-
return this._invert(BeamDirection.Up);
|
|
61127
|
-
}
|
|
61128
|
-
// grace notes are always up
|
|
61129
|
-
if (this.beats[0].graceType !== GraceType.None) {
|
|
61130
|
-
return this._invert(BeamDirection.Up);
|
|
61131
|
-
}
|
|
61132
|
-
// the average line is used for determination
|
|
61133
|
-
// key lowerequal than middle line -> up
|
|
61134
|
-
// key higher than middle line -> down
|
|
61135
|
-
if (this.highestNoteInHelper && this.lowestNoteInHelper) {
|
|
61136
|
-
const highestNotePosition = this._renderer.getNoteY(this.highestNoteInHelper, NoteYPosition.Center);
|
|
61137
|
-
const lowestNotePosition = this._renderer.getNoteY(this.lowestNoteInHelper, NoteYPosition.Center);
|
|
61138
|
-
const avg = (highestNotePosition + lowestNotePosition) / 2;
|
|
61139
|
-
return this._invert(this._renderer.middleYPosition < avg ? BeamDirection.Up : BeamDirection.Down);
|
|
61140
|
-
}
|
|
61141
|
-
return this._invert(BeamDirection.Up);
|
|
61142
|
-
}
|
|
61143
61387
|
static computeLineHeightsForRest(duration) {
|
|
61144
61388
|
switch (duration) {
|
|
61145
61389
|
case Duration.QuadrupleWhole:
|
|
@@ -61167,18 +61411,6 @@
|
|
|
61167
61411
|
}
|
|
61168
61412
|
return [0, 0];
|
|
61169
61413
|
}
|
|
61170
|
-
_invert(direction) {
|
|
61171
|
-
if (!this.invertBeamDirection) {
|
|
61172
|
-
return direction;
|
|
61173
|
-
}
|
|
61174
|
-
switch (direction) {
|
|
61175
|
-
case BeamDirection.Down:
|
|
61176
|
-
return BeamDirection.Up;
|
|
61177
|
-
// case BeamDirection.Up:
|
|
61178
|
-
default:
|
|
61179
|
-
return BeamDirection.Down;
|
|
61180
|
-
}
|
|
61181
|
-
}
|
|
61182
61414
|
checkBeat(beat) {
|
|
61183
61415
|
if (beat.invertBeamDirection) {
|
|
61184
61416
|
this.invertBeamDirection = true;
|
|
@@ -61212,11 +61444,6 @@
|
|
|
61212
61444
|
if (beat.hasTuplet) {
|
|
61213
61445
|
this.hasTuplet = true;
|
|
61214
61446
|
}
|
|
61215
|
-
if (beat.isTremolo) {
|
|
61216
|
-
if (!this.tremoloDuration || this.tremoloDuration < beat.tremoloSpeed) {
|
|
61217
|
-
this.tremoloDuration = beat.tremoloSpeed;
|
|
61218
|
-
}
|
|
61219
|
-
}
|
|
61220
61447
|
if (beat.graceType !== GraceType.None) {
|
|
61221
61448
|
this.graceType = beat.graceType;
|
|
61222
61449
|
}
|
|
@@ -62115,9 +62342,6 @@
|
|
|
62115
62342
|
}
|
|
62116
62343
|
completeBeamingHelper(_helper) {
|
|
62117
62344
|
}
|
|
62118
|
-
getBeatDirection(beat) {
|
|
62119
|
-
return this.helpers.getBeamingHelperForBeat(beat)?.direction ?? BeamDirection.Up;
|
|
62120
|
-
}
|
|
62121
62345
|
}
|
|
62122
62346
|
|
|
62123
62347
|
/**
|
|
@@ -67200,11 +67424,11 @@
|
|
|
67200
67424
|
beatBounds.addNote(noteBounds);
|
|
67201
67425
|
}
|
|
67202
67426
|
}
|
|
67203
|
-
getLowestNoteY() {
|
|
67204
|
-
return this._internalGetNoteY(
|
|
67427
|
+
getLowestNoteY(requestedPosition) {
|
|
67428
|
+
return this._internalGetNoteY(requestedPosition);
|
|
67205
67429
|
}
|
|
67206
|
-
getHighestNoteY() {
|
|
67207
|
-
return this._internalGetNoteY(
|
|
67430
|
+
getHighestNoteY(requestedPosition) {
|
|
67431
|
+
return this._internalGetNoteY(requestedPosition);
|
|
67208
67432
|
}
|
|
67209
67433
|
getNoteY(_note, requestedPosition) {
|
|
67210
67434
|
return this._internalGetNoteY(requestedPosition);
|
|
@@ -67653,6 +67877,12 @@
|
|
|
67653
67877
|
get isLastOfVoice() {
|
|
67654
67878
|
return false;
|
|
67655
67879
|
}
|
|
67880
|
+
getLowestNoteY(_requestedPosition) {
|
|
67881
|
+
return 0;
|
|
67882
|
+
}
|
|
67883
|
+
getHighestNoteY(_requestedPosition) {
|
|
67884
|
+
return 0;
|
|
67885
|
+
}
|
|
67656
67886
|
getNoteY(_note, _requestedPosition) {
|
|
67657
67887
|
return 0;
|
|
67658
67888
|
}
|
|
@@ -67804,6 +68034,11 @@
|
|
|
67804
68034
|
constructor(x, y, duration, direction, isGrace) {
|
|
67805
68035
|
super(x, y, isGrace ? EngravingSettings.GraceScale : 1, FlagGlyph.getSymbol(duration, direction, isGrace));
|
|
67806
68036
|
}
|
|
68037
|
+
paint(cx, cy, canvas) {
|
|
68038
|
+
const c = canvas.color;
|
|
68039
|
+
super.paint(cx, cy, canvas);
|
|
68040
|
+
canvas.color = c;
|
|
68041
|
+
}
|
|
67807
68042
|
static getSymbol(duration, direction, isGrace) {
|
|
67808
68043
|
if (isGrace) {
|
|
67809
68044
|
duration = Duration.Eighth;
|
|
@@ -68008,9 +68243,17 @@
|
|
|
68008
68243
|
}
|
|
68009
68244
|
}
|
|
68010
68245
|
}
|
|
68246
|
+
getBeatDirection(beat) {
|
|
68247
|
+
const helper = this.helpers.getBeamingHelperForBeat(beat);
|
|
68248
|
+
return helper ? this.getBeamDirection(helper) : BeamDirection.Up;
|
|
68249
|
+
}
|
|
68011
68250
|
getTupletBeamDirection(helper) {
|
|
68012
68251
|
return this.getBeamDirection(helper);
|
|
68013
68252
|
}
|
|
68253
|
+
calculateBeamYWithDirection(h, x, direction) {
|
|
68254
|
+
this.ensureBeamDrawingInfo(h, direction);
|
|
68255
|
+
return h.drawingInfos.get(direction).calcY(x);
|
|
68256
|
+
}
|
|
68014
68257
|
_paintTupletHelper(cx, cy, canvas, h, beatElement, bracketsAsArcs) {
|
|
68015
68258
|
const res = this.resources;
|
|
68016
68259
|
const oldAlign = canvas.textAlign;
|
|
@@ -68319,26 +68562,6 @@
|
|
|
68319
68562
|
}
|
|
68320
68563
|
}
|
|
68321
68564
|
}
|
|
68322
|
-
getFlagStemSize(duration, forceMinStem = false) {
|
|
68323
|
-
let size = 0;
|
|
68324
|
-
switch (duration) {
|
|
68325
|
-
case Duration.QuadrupleWhole:
|
|
68326
|
-
case Duration.Half:
|
|
68327
|
-
case Duration.Quarter:
|
|
68328
|
-
case Duration.Eighth:
|
|
68329
|
-
case Duration.Sixteenth:
|
|
68330
|
-
case Duration.ThirtySecond:
|
|
68331
|
-
case Duration.SixtyFourth:
|
|
68332
|
-
case Duration.OneHundredTwentyEighth:
|
|
68333
|
-
case Duration.TwoHundredFiftySixth:
|
|
68334
|
-
size = this.smuflMetrics.standardStemLength + this.smuflMetrics.stemFlagOffsets.get(duration);
|
|
68335
|
-
break;
|
|
68336
|
-
default:
|
|
68337
|
-
size = forceMinStem ? this.smuflMetrics.standardStemLength : 0;
|
|
68338
|
-
break;
|
|
68339
|
-
}
|
|
68340
|
-
return size;
|
|
68341
|
-
}
|
|
68342
68565
|
recreatePreBeatGlyphs() {
|
|
68343
68566
|
this._startSpacing = false;
|
|
68344
68567
|
super.recreatePreBeatGlyphs();
|
|
@@ -68350,6 +68573,9 @@
|
|
|
68350
68573
|
super.createPreBeatGlyphs();
|
|
68351
68574
|
this.addPreBeatGlyph(new BarLineGlyph(false, this.bar.staff.track.score.stylesheet.extendBarLines));
|
|
68352
68575
|
this.createLinePreBeatGlyphs();
|
|
68576
|
+
if (this.index === 0) {
|
|
68577
|
+
this.createStartSpacing();
|
|
68578
|
+
}
|
|
68353
68579
|
this.addPreBeatGlyph(new BarNumberGlyph(0, this.getLineHeight(-0.5), this.bar.index + 1));
|
|
68354
68580
|
}
|
|
68355
68581
|
createPostBeatGlyphs() {
|
|
@@ -68376,7 +68602,13 @@
|
|
|
68376
68602
|
continue;
|
|
68377
68603
|
}
|
|
68378
68604
|
const beatLineX = this.getBeatX(beat, BeatXPosition.Stem);
|
|
68379
|
-
|
|
68605
|
+
let y1 = cy + this.y;
|
|
68606
|
+
if (direction === BeamDirection.Up) {
|
|
68607
|
+
y1 += this.getFlagBottomY(beat, direction);
|
|
68608
|
+
}
|
|
68609
|
+
else {
|
|
68610
|
+
y1 += this.getFlagTopY(beat, direction);
|
|
68611
|
+
}
|
|
68380
68612
|
// ensure we are pixel aligned on the end of the stem to avoid anti-aliasing artifacts
|
|
68381
68613
|
// when combining stems and beams on sub-pixel level
|
|
68382
68614
|
const y2 = (cy + this.y + this.calculateBeamY(h, beatLineX)) | 0;
|
|
@@ -68482,21 +68714,22 @@
|
|
|
68482
68714
|
calculateBeamingOverflows(rendererTop, rendererBottom) {
|
|
68483
68715
|
let maxNoteY = 0;
|
|
68484
68716
|
let minNoteY = 0;
|
|
68485
|
-
const noteOverflowPadding = this.getLineHeight(0.5);
|
|
68486
68717
|
for (const v of this.helpers.beamHelpers) {
|
|
68487
68718
|
for (const h of v) {
|
|
68488
68719
|
if (!this.shouldPaintBeamingHelper(h)) ;
|
|
68489
68720
|
else if (h.beats.length === 1 && h.beats[0].duration >= Duration.Half) {
|
|
68490
68721
|
const tupletDirection = this.getTupletBeamDirection(h);
|
|
68491
|
-
|
|
68492
|
-
|
|
68493
|
-
|
|
68722
|
+
const direction = this.getBeamDirection(h);
|
|
68723
|
+
const flagOverflow = this.smuflMetrics.stemFlagOffsets.get(h.beats[0].duration);
|
|
68724
|
+
if (direction === BeamDirection.Up) {
|
|
68725
|
+
let topY = this.getFlagTopY(h.beats[0], direction) - flagOverflow;
|
|
68726
|
+
if (h.hasTuplet && tupletDirection === direction) {
|
|
68494
68727
|
topY -= this.tupletSize + this.tupletOffset;
|
|
68495
68728
|
}
|
|
68496
68729
|
if (topY < maxNoteY) {
|
|
68497
68730
|
maxNoteY = topY;
|
|
68498
68731
|
}
|
|
68499
|
-
if (h.hasTuplet && tupletDirection !==
|
|
68732
|
+
if (h.hasTuplet && tupletDirection !== direction) {
|
|
68500
68733
|
let bottomY = this.getFlagBottomY(h.beats[0], tupletDirection);
|
|
68501
68734
|
bottomY += this.tupletSize + this.tupletOffset;
|
|
68502
68735
|
if (bottomY > minNoteY) {
|
|
@@ -68505,14 +68738,14 @@
|
|
|
68505
68738
|
}
|
|
68506
68739
|
}
|
|
68507
68740
|
else {
|
|
68508
|
-
let bottomY = this.getFlagBottomY(h.beats[0],
|
|
68509
|
-
if (h.hasTuplet && tupletDirection ===
|
|
68741
|
+
let bottomY = this.getFlagBottomY(h.beats[0], direction) + flagOverflow;
|
|
68742
|
+
if (h.hasTuplet && tupletDirection === direction) {
|
|
68510
68743
|
bottomY += this.tupletSize + this.tupletOffset;
|
|
68511
68744
|
}
|
|
68512
68745
|
if (bottomY > minNoteY) {
|
|
68513
68746
|
minNoteY = bottomY;
|
|
68514
68747
|
}
|
|
68515
|
-
if (h.hasTuplet && tupletDirection !==
|
|
68748
|
+
if (h.hasTuplet && tupletDirection !== direction) {
|
|
68516
68749
|
let topY = this.getFlagTopY(h.beats[0], tupletDirection);
|
|
68517
68750
|
topY -= this.tupletSize + this.tupletOffset;
|
|
68518
68751
|
if (topY < maxNoteY) {
|
|
@@ -68522,19 +68755,20 @@
|
|
|
68522
68755
|
}
|
|
68523
68756
|
}
|
|
68524
68757
|
else {
|
|
68525
|
-
this.
|
|
68526
|
-
|
|
68758
|
+
const direction = this.getBeamDirection(h);
|
|
68759
|
+
this.ensureBeamDrawingInfo(h, direction);
|
|
68760
|
+
const drawingInfo = h.drawingInfos.get(direction);
|
|
68527
68761
|
const tupletDirection = this.getTupletBeamDirection(h);
|
|
68528
|
-
if (
|
|
68762
|
+
if (direction === BeamDirection.Up) {
|
|
68529
68763
|
let topY = Math.min(drawingInfo.startY, drawingInfo.endY);
|
|
68530
|
-
if (h.hasTuplet && tupletDirection ===
|
|
68764
|
+
if (h.hasTuplet && tupletDirection === direction) {
|
|
68531
68765
|
topY -= this.tupletSize + this.tupletOffset;
|
|
68532
68766
|
}
|
|
68533
68767
|
if (topY < maxNoteY) {
|
|
68534
68768
|
maxNoteY = topY;
|
|
68535
68769
|
}
|
|
68536
|
-
let bottomY = this.
|
|
68537
|
-
if (h.hasTuplet && tupletDirection !==
|
|
68770
|
+
let bottomY = this.voiceContainer.getLowestNoteY(h.beatOfLowestNote, NoteYPosition.Bottom);
|
|
68771
|
+
if (h.hasTuplet && tupletDirection !== direction) {
|
|
68538
68772
|
bottomY += this.tupletSize + this.tupletOffset;
|
|
68539
68773
|
}
|
|
68540
68774
|
if (bottomY > minNoteY) {
|
|
@@ -68543,14 +68777,14 @@
|
|
|
68543
68777
|
}
|
|
68544
68778
|
else {
|
|
68545
68779
|
let bottomY = Math.max(drawingInfo.startY, drawingInfo.endY);
|
|
68546
|
-
if (h.hasTuplet && tupletDirection ===
|
|
68780
|
+
if (h.hasTuplet && tupletDirection === direction) {
|
|
68547
68781
|
bottomY += this.tupletSize + this.tupletOffset;
|
|
68548
68782
|
}
|
|
68549
68783
|
if (bottomY > minNoteY) {
|
|
68550
68784
|
minNoteY = bottomY;
|
|
68551
68785
|
}
|
|
68552
|
-
let topY = this.
|
|
68553
|
-
if (h.hasTuplet && tupletDirection !==
|
|
68786
|
+
let topY = this.voiceContainer.getHighestNoteY(h.beatOfHighestNote, NoteYPosition.Top);
|
|
68787
|
+
if (h.hasTuplet && tupletDirection !== direction) {
|
|
68554
68788
|
topY -= this.tupletSize + this.tupletOffset;
|
|
68555
68789
|
}
|
|
68556
68790
|
if (topY < maxNoteY) {
|
|
@@ -68627,38 +68861,11 @@
|
|
|
68627
68861
|
// 3. any middle elements (notes or rests) shift this diagonal line up/down to avoid overlaps
|
|
68628
68862
|
const drawingInfo = this.initializeBeamDrawingInfo(h, direction);
|
|
68629
68863
|
h.drawingInfos.set(direction, drawingInfo);
|
|
68630
|
-
const isRest = h.isRestBeamHelper;
|
|
68631
|
-
const scale = h.graceType !== GraceType.None ? EngravingSettings.GraceScale : 1;
|
|
68632
68864
|
const barCount = ModelUtils.getIndex(h.shortestDuration) - 2;
|
|
68633
68865
|
// 3. adjust beam drawing order
|
|
68634
68866
|
// we can only draw up to 2 beams towards the noteheads, then we have to grow to the other side
|
|
68635
68867
|
// here we shift accordingly
|
|
68636
|
-
|
|
68637
|
-
if (barCount > 2 && !isRest) {
|
|
68638
|
-
const beamSpacing = this.beamSpacing * scale;
|
|
68639
|
-
const beamThickness = this.beamThickness * scale;
|
|
68640
|
-
const totalBarsHeight = barCount * beamThickness + (barCount - 1) * beamSpacing;
|
|
68641
|
-
if (direction === BeamDirection.Up) {
|
|
68642
|
-
const bottomBarY = drawingInfo.startY + 2 * beamThickness + beamSpacing;
|
|
68643
|
-
const barTopY = bottomBarY - totalBarsHeight;
|
|
68644
|
-
const diff = drawingInfo.startY - barTopY;
|
|
68645
|
-
if (diff > 0) {
|
|
68646
|
-
barDrawingShift = diff * -1;
|
|
68647
|
-
drawingInfo.startY -= diff;
|
|
68648
|
-
drawingInfo.endY -= diff;
|
|
68649
|
-
}
|
|
68650
|
-
}
|
|
68651
|
-
else {
|
|
68652
|
-
const topBarY = drawingInfo.startY - 2 * beamThickness + beamSpacing;
|
|
68653
|
-
const barBottomY = topBarY + totalBarsHeight;
|
|
68654
|
-
const diff = barBottomY - drawingInfo.startY;
|
|
68655
|
-
if (diff > 0) {
|
|
68656
|
-
barDrawingShift = diff;
|
|
68657
|
-
drawingInfo.startY += diff;
|
|
68658
|
-
drawingInfo.endY += diff;
|
|
68659
|
-
}
|
|
68660
|
-
}
|
|
68661
|
-
}
|
|
68868
|
+
const barDrawingShift = this.applyBarShift(h, direction, drawingInfo, barCount);
|
|
68662
68869
|
// 4. let middle elements shift up/down
|
|
68663
68870
|
if (h.beats.length > 1) {
|
|
68664
68871
|
// check if highest note shifts bar up or down
|
|
@@ -68714,9 +68921,9 @@
|
|
|
68714
68921
|
if (h.slashBeats.length > 0) {
|
|
68715
68922
|
for (const b of h.slashBeats) {
|
|
68716
68923
|
const yGivenByCurrentValues = drawingInfo.calcY(this.getBeatX(b, BeatXPosition.Stem));
|
|
68717
|
-
const yNeededForSlash =
|
|
68718
|
-
? this.getFlagTopY(b,
|
|
68719
|
-
: this.getFlagBottomY(b,
|
|
68924
|
+
const yNeededForSlash = direction === BeamDirection.Up
|
|
68925
|
+
? this.getFlagTopY(b, direction)
|
|
68926
|
+
: this.getFlagBottomY(b, direction);
|
|
68720
68927
|
const diff = yNeededForSlash - yGivenByCurrentValues;
|
|
68721
68928
|
if (diff > 0) {
|
|
68722
68929
|
drawingInfo.startY += diff;
|
|
@@ -68726,6 +68933,37 @@
|
|
|
68726
68933
|
}
|
|
68727
68934
|
}
|
|
68728
68935
|
}
|
|
68936
|
+
applyBarShift(h, direction, drawingInfo, barCount) {
|
|
68937
|
+
let barDrawingShift = 0;
|
|
68938
|
+
const isRest = h.isRestBeamHelper;
|
|
68939
|
+
const scale = h.graceType !== GraceType.None ? EngravingSettings.GraceScale : 1;
|
|
68940
|
+
if (barCount > 2 && !isRest) {
|
|
68941
|
+
const beamSpacing = this.beamSpacing * scale;
|
|
68942
|
+
const beamThickness = this.beamThickness * scale;
|
|
68943
|
+
const totalBarsHeight = barCount * beamThickness + (barCount - 1) * beamSpacing;
|
|
68944
|
+
if (direction === BeamDirection.Up) {
|
|
68945
|
+
const bottomBarY = drawingInfo.startY + 2 * beamThickness + beamSpacing;
|
|
68946
|
+
const barTopY = bottomBarY - totalBarsHeight;
|
|
68947
|
+
const diff = drawingInfo.startY - barTopY;
|
|
68948
|
+
if (diff > 0) {
|
|
68949
|
+
barDrawingShift = diff * -1;
|
|
68950
|
+
drawingInfo.startY -= diff;
|
|
68951
|
+
drawingInfo.endY -= diff;
|
|
68952
|
+
}
|
|
68953
|
+
}
|
|
68954
|
+
else {
|
|
68955
|
+
const topBarY = drawingInfo.startY - 2 * beamThickness + beamSpacing;
|
|
68956
|
+
const barBottomY = topBarY + totalBarsHeight;
|
|
68957
|
+
const diff = barBottomY - drawingInfo.startY;
|
|
68958
|
+
if (diff > 0) {
|
|
68959
|
+
barDrawingShift = diff;
|
|
68960
|
+
drawingInfo.startY += diff;
|
|
68961
|
+
drawingInfo.endY += diff;
|
|
68962
|
+
}
|
|
68963
|
+
}
|
|
68964
|
+
}
|
|
68965
|
+
return barDrawingShift;
|
|
68966
|
+
}
|
|
68729
68967
|
getMinLineOfBeat(_beat) {
|
|
68730
68968
|
return 0;
|
|
68731
68969
|
}
|
|
@@ -68829,7 +69067,9 @@
|
|
|
68829
69067
|
for (const additionalNumber of container.iterateAdditionalNumbers()) {
|
|
68830
69068
|
barCount = additionalNumber.barCount;
|
|
68831
69069
|
beatLineX =
|
|
68832
|
-
this.beatGlyphsStart +
|
|
69070
|
+
this.beatGlyphsStart +
|
|
69071
|
+
additionalNumber.x +
|
|
69072
|
+
additionalNumber.getBeatX(BeatXPosition.PreNotes, false);
|
|
68833
69073
|
for (let barIndex = 0; barIndex < barCount; barIndex++) {
|
|
68834
69074
|
const barY = barStart + barIndex * barSpacing;
|
|
68835
69075
|
const additionalBarEndX = this.beatGlyphsStart +
|
|
@@ -68894,44 +69134,12 @@
|
|
|
68894
69134
|
}
|
|
68895
69135
|
return this.getLineY(0);
|
|
68896
69136
|
}
|
|
68897
|
-
completeBeamingHelper(helper) {
|
|
68898
|
-
super.completeBeamingHelper(helper);
|
|
68899
|
-
helper.direction = BeamDirection.Down;
|
|
68900
|
-
}
|
|
68901
69137
|
getBeamDirection(_helper) {
|
|
68902
69138
|
return BeamDirection.Down;
|
|
68903
69139
|
}
|
|
68904
69140
|
getTupletBeamDirection(_helper) {
|
|
68905
69141
|
return BeamDirection.Up;
|
|
68906
69142
|
}
|
|
68907
|
-
getNoteY(note, requestedPosition) {
|
|
68908
|
-
let y = super.getNoteY(note, requestedPosition);
|
|
68909
|
-
if (Number.isNaN(y)) {
|
|
68910
|
-
y = this.getLineY(0);
|
|
68911
|
-
}
|
|
68912
|
-
return y;
|
|
68913
|
-
}
|
|
68914
|
-
calculateBeamYWithDirection(h, _x, direction) {
|
|
68915
|
-
if (h.beats.length === 0) {
|
|
68916
|
-
return this.getLineY(0);
|
|
68917
|
-
}
|
|
68918
|
-
this.ensureBeamDrawingInfo(h, direction);
|
|
68919
|
-
const info = h.drawingInfos.get(direction);
|
|
68920
|
-
if (direction === BeamDirection.Up) {
|
|
68921
|
-
return Math.min(info.startY, info.endY);
|
|
68922
|
-
}
|
|
68923
|
-
else {
|
|
68924
|
-
return Math.max(info.startY, info.endY);
|
|
68925
|
-
}
|
|
68926
|
-
}
|
|
68927
|
-
getBarLineStart(beat, _direction) {
|
|
68928
|
-
// NOTE: this is only for the overflow calculation, this renderer has a custom bar drawing logic
|
|
68929
|
-
const container = this.voiceContainer.getBeatContainer(beat);
|
|
68930
|
-
if (!container) {
|
|
68931
|
-
return this.voiceContainer.getBoundingBoxTop();
|
|
68932
|
-
}
|
|
68933
|
-
return container.getBoundingBoxTop();
|
|
68934
|
-
}
|
|
68935
69143
|
createPreBeatGlyphs() {
|
|
68936
69144
|
this.wasFirstOfStaff = this.isFirstOfStaff;
|
|
68937
69145
|
if (this.index === 0 || (this.bar.masterBar.isRepeatStart && this._isOnlyNumbered)) {
|
|
@@ -69014,6 +69222,19 @@
|
|
|
69014
69222
|
super.paintBeamHelper(cx, cy, canvas, h, flagsElement, beamsElement);
|
|
69015
69223
|
}
|
|
69016
69224
|
}
|
|
69225
|
+
applyBarShift(_h, _direction, _drawingInfo, _barCount) {
|
|
69226
|
+
return 0;
|
|
69227
|
+
}
|
|
69228
|
+
calculateBeamYWithDirection(h, _x, direction) {
|
|
69229
|
+
this.ensureBeamDrawingInfo(h, direction);
|
|
69230
|
+
const info = h.drawingInfos.get(direction);
|
|
69231
|
+
if (direction === BeamDirection.Up) {
|
|
69232
|
+
return Math.min(info.startY, info.endY);
|
|
69233
|
+
}
|
|
69234
|
+
else {
|
|
69235
|
+
return Math.max(info.startY, info.endY);
|
|
69236
|
+
}
|
|
69237
|
+
}
|
|
69017
69238
|
}
|
|
69018
69239
|
|
|
69019
69240
|
/**
|
|
@@ -69182,132 +69403,6 @@
|
|
|
69182
69403
|
}
|
|
69183
69404
|
}
|
|
69184
69405
|
|
|
69185
|
-
/**
|
|
69186
|
-
* @internal
|
|
69187
|
-
*/
|
|
69188
|
-
class NoteHeadGlyphBase extends MusicFontGlyph {
|
|
69189
|
-
centerOnStem = false;
|
|
69190
|
-
constructor(x, y, isGrace, symbol) {
|
|
69191
|
-
super(x, y, isGrace ? EngravingSettings.GraceScale : 1, symbol);
|
|
69192
|
-
}
|
|
69193
|
-
paint(cx, cy, canvas) {
|
|
69194
|
-
if (this.centerOnStem) {
|
|
69195
|
-
this.center = true;
|
|
69196
|
-
}
|
|
69197
|
-
super.paint(cx, cy, canvas);
|
|
69198
|
-
}
|
|
69199
|
-
}
|
|
69200
|
-
/**
|
|
69201
|
-
* @internal
|
|
69202
|
-
*/
|
|
69203
|
-
class NoteHeadGlyph extends NoteHeadGlyphBase {
|
|
69204
|
-
constructor(x, y, duration, isGrace) {
|
|
69205
|
-
super(x, y, isGrace, NoteHeadGlyph.getSymbol(duration));
|
|
69206
|
-
}
|
|
69207
|
-
static getSymbol(duration) {
|
|
69208
|
-
switch (duration) {
|
|
69209
|
-
case Duration.QuadrupleWhole:
|
|
69210
|
-
return MusicFontSymbol.NoteheadDoubleWholeSquare;
|
|
69211
|
-
case Duration.DoubleWhole:
|
|
69212
|
-
return MusicFontSymbol.NoteheadDoubleWhole;
|
|
69213
|
-
case Duration.Whole:
|
|
69214
|
-
return MusicFontSymbol.NoteheadWhole;
|
|
69215
|
-
case Duration.Half:
|
|
69216
|
-
return MusicFontSymbol.NoteheadHalf;
|
|
69217
|
-
default:
|
|
69218
|
-
return MusicFontSymbol.NoteheadBlack;
|
|
69219
|
-
}
|
|
69220
|
-
}
|
|
69221
|
-
}
|
|
69222
|
-
|
|
69223
|
-
/**
|
|
69224
|
-
* @internal
|
|
69225
|
-
*/
|
|
69226
|
-
class SlashNoteHeadGlyph extends NoteHeadGlyphBase {
|
|
69227
|
-
beatEffects = new Map();
|
|
69228
|
-
noteHeadElement = NoteSubElement.SlashNoteHead;
|
|
69229
|
-
effectElement = BeatSubElement.SlashEffects;
|
|
69230
|
-
_symbol;
|
|
69231
|
-
stemX = 0;
|
|
69232
|
-
constructor(x, y, duration, isGrace, beat) {
|
|
69233
|
-
super(x, y, isGrace, SlashNoteHeadGlyph.getSymbol(duration));
|
|
69234
|
-
this._symbol = SlashNoteHeadGlyph.getSymbol(duration);
|
|
69235
|
-
this.beat = beat;
|
|
69236
|
-
}
|
|
69237
|
-
paint(cx, cy, canvas) {
|
|
69238
|
-
const _ = this.beat.notes.length === 0
|
|
69239
|
-
? undefined
|
|
69240
|
-
: ElementStyleHelper.note(canvas, this.noteHeadElement, this.beat.notes[0]);
|
|
69241
|
-
try {
|
|
69242
|
-
super.paint(cx, cy, canvas);
|
|
69243
|
-
this._paintEffects(cx, cy, canvas);
|
|
69244
|
-
}
|
|
69245
|
-
finally {
|
|
69246
|
-
_?.[Symbol.dispose]?.();
|
|
69247
|
-
}
|
|
69248
|
-
}
|
|
69249
|
-
_paintEffects(cx, cy, canvas) {
|
|
69250
|
-
const _ = ElementStyleHelper.beat(canvas, this.effectElement, this.beat);
|
|
69251
|
-
try {
|
|
69252
|
-
for (const g of this.beatEffects.values()) {
|
|
69253
|
-
g.paint(cx + this.x, cy + this.y, canvas);
|
|
69254
|
-
}
|
|
69255
|
-
}
|
|
69256
|
-
finally {
|
|
69257
|
-
_?.[Symbol.dispose]?.();
|
|
69258
|
-
}
|
|
69259
|
-
}
|
|
69260
|
-
doLayout() {
|
|
69261
|
-
super.doLayout();
|
|
69262
|
-
const effectSpacing = this.renderer.smuflMetrics.onNoteEffectPadding;
|
|
69263
|
-
let effectY = this.renderer.smuflMetrics.glyphHeights.get(this._symbol);
|
|
69264
|
-
let minEffectY = Number.NaN;
|
|
69265
|
-
let maxEffectY = Number.NaN;
|
|
69266
|
-
for (const g of this.beatEffects.values()) {
|
|
69267
|
-
g.y += effectY;
|
|
69268
|
-
g.x += this.width / 2;
|
|
69269
|
-
g.renderer = this.renderer;
|
|
69270
|
-
effectY += g.height + effectSpacing;
|
|
69271
|
-
g.doLayout();
|
|
69272
|
-
if (Number.isNaN(minEffectY) || minEffectY > effectY) {
|
|
69273
|
-
minEffectY = effectY;
|
|
69274
|
-
}
|
|
69275
|
-
if (Number.isNaN(maxEffectY) || maxEffectY < effectY) {
|
|
69276
|
-
maxEffectY = effectY;
|
|
69277
|
-
}
|
|
69278
|
-
}
|
|
69279
|
-
if (!Number.isNaN(minEffectY)) {
|
|
69280
|
-
this.renderer.registerBeatEffectOverflows(minEffectY, maxEffectY);
|
|
69281
|
-
}
|
|
69282
|
-
const direction = this.renderer.getBeatDirection(this.beat);
|
|
69283
|
-
const symbol = this._symbol;
|
|
69284
|
-
if (direction === BeamDirection.Up) {
|
|
69285
|
-
const stemInfoUp = this.renderer.smuflMetrics.stemUp.has(symbol)
|
|
69286
|
-
? this.renderer.smuflMetrics.stemUp.get(symbol).x
|
|
69287
|
-
: 0;
|
|
69288
|
-
this.stemX = stemInfoUp;
|
|
69289
|
-
}
|
|
69290
|
-
else {
|
|
69291
|
-
const stemInfoDown = this.renderer.smuflMetrics.stemDown.has(symbol)
|
|
69292
|
-
? this.renderer.smuflMetrics.stemDown.get(symbol).x
|
|
69293
|
-
: 0;
|
|
69294
|
-
this.stemX = stemInfoDown;
|
|
69295
|
-
}
|
|
69296
|
-
}
|
|
69297
|
-
static getSymbol(duration) {
|
|
69298
|
-
switch (duration) {
|
|
69299
|
-
case Duration.QuadrupleWhole:
|
|
69300
|
-
case Duration.DoubleWhole:
|
|
69301
|
-
case Duration.Whole:
|
|
69302
|
-
return MusicFontSymbol.NoteheadSlashWhiteWhole;
|
|
69303
|
-
case Duration.Half:
|
|
69304
|
-
return MusicFontSymbol.NoteheadSlashWhiteHalf;
|
|
69305
|
-
default:
|
|
69306
|
-
return MusicFontSymbol.NoteheadSlashHorizontalEnds;
|
|
69307
|
-
}
|
|
69308
|
-
}
|
|
69309
|
-
}
|
|
69310
|
-
|
|
69311
69406
|
/**
|
|
69312
69407
|
* @internal
|
|
69313
69408
|
*/
|
|
@@ -69357,6 +69452,44 @@
|
|
|
69357
69452
|
}
|
|
69358
69453
|
}
|
|
69359
69454
|
|
|
69455
|
+
/**
|
|
69456
|
+
* @internal
|
|
69457
|
+
*/
|
|
69458
|
+
class NoteHeadGlyphBase extends MusicFontGlyph {
|
|
69459
|
+
centerOnStem = false;
|
|
69460
|
+
constructor(x, y, isGrace, symbol) {
|
|
69461
|
+
super(x, y, isGrace ? EngravingSettings.GraceScale : 1, symbol);
|
|
69462
|
+
}
|
|
69463
|
+
paint(cx, cy, canvas) {
|
|
69464
|
+
if (this.centerOnStem) {
|
|
69465
|
+
this.center = true;
|
|
69466
|
+
}
|
|
69467
|
+
super.paint(cx, cy, canvas);
|
|
69468
|
+
}
|
|
69469
|
+
}
|
|
69470
|
+
/**
|
|
69471
|
+
* @internal
|
|
69472
|
+
*/
|
|
69473
|
+
class NoteHeadGlyph extends NoteHeadGlyphBase {
|
|
69474
|
+
constructor(x, y, duration, isGrace) {
|
|
69475
|
+
super(x, y, isGrace, NoteHeadGlyph.getSymbol(duration));
|
|
69476
|
+
}
|
|
69477
|
+
static getSymbol(duration) {
|
|
69478
|
+
switch (duration) {
|
|
69479
|
+
case Duration.QuadrupleWhole:
|
|
69480
|
+
return MusicFontSymbol.NoteheadDoubleWholeSquare;
|
|
69481
|
+
case Duration.DoubleWhole:
|
|
69482
|
+
return MusicFontSymbol.NoteheadDoubleWhole;
|
|
69483
|
+
case Duration.Whole:
|
|
69484
|
+
return MusicFontSymbol.NoteheadWhole;
|
|
69485
|
+
case Duration.Half:
|
|
69486
|
+
return MusicFontSymbol.NoteheadHalf;
|
|
69487
|
+
default:
|
|
69488
|
+
return MusicFontSymbol.NoteheadBlack;
|
|
69489
|
+
}
|
|
69490
|
+
}
|
|
69491
|
+
}
|
|
69492
|
+
|
|
69360
69493
|
/**
|
|
69361
69494
|
* @internal
|
|
69362
69495
|
*/
|
|
@@ -69720,8 +69853,8 @@
|
|
|
69720
69853
|
_infos = [];
|
|
69721
69854
|
_noteHeadInfo;
|
|
69722
69855
|
noteGroup;
|
|
69723
|
-
|
|
69724
|
-
|
|
69856
|
+
minStepsNote = null;
|
|
69857
|
+
maxStepsNote = null;
|
|
69725
69858
|
get stemX() {
|
|
69726
69859
|
if (!this.noteGroup) {
|
|
69727
69860
|
return 0;
|
|
@@ -69734,25 +69867,19 @@
|
|
|
69734
69867
|
super(0, 0);
|
|
69735
69868
|
}
|
|
69736
69869
|
getBoundingBoxTop() {
|
|
69737
|
-
return this.
|
|
69870
|
+
return this.minStepsNote ? this.minStepsNote.glyph.getBoundingBoxTop() : this.y;
|
|
69738
69871
|
}
|
|
69739
69872
|
getBoundingBoxBottom() {
|
|
69740
|
-
return this.
|
|
69741
|
-
}
|
|
69742
|
-
getLowestNoteY() {
|
|
69743
|
-
return this.maxNote ? this.renderer.getScoreY(this.maxNote.steps) : 0;
|
|
69744
|
-
}
|
|
69745
|
-
getHighestNoteY() {
|
|
69746
|
-
return this.minNote ? this.renderer.getScoreY(this.minNote.steps) : 0;
|
|
69873
|
+
return this.maxStepsNote ? this.maxStepsNote.glyph.getBoundingBoxBottom() : this.y + this.height;
|
|
69747
69874
|
}
|
|
69748
69875
|
add(noteGlyph, noteSteps) {
|
|
69749
69876
|
const info = { glyph: noteGlyph, steps: noteSteps };
|
|
69750
69877
|
this._infos.push(info);
|
|
69751
|
-
if (!this.
|
|
69752
|
-
this.
|
|
69878
|
+
if (!this.minStepsNote || this.minStepsNote.steps > info.steps) {
|
|
69879
|
+
this.minStepsNote = info;
|
|
69753
69880
|
}
|
|
69754
|
-
if (!this.
|
|
69755
|
-
this.
|
|
69881
|
+
if (!this.maxStepsNote || this.maxStepsNote.steps < info.steps) {
|
|
69882
|
+
this.maxStepsNote = info;
|
|
69756
69883
|
}
|
|
69757
69884
|
}
|
|
69758
69885
|
_prepareForLayout(info) {
|
|
@@ -69988,7 +70115,7 @@
|
|
|
69988
70115
|
}
|
|
69989
70116
|
}
|
|
69990
70117
|
_paintLedgerLines(cx, cy, canvas) {
|
|
69991
|
-
if (!this.
|
|
70118
|
+
if (!this.minStepsNote) {
|
|
69992
70119
|
return;
|
|
69993
70120
|
}
|
|
69994
70121
|
const scoreRenderer = this.renderer;
|
|
@@ -70000,8 +70127,8 @@
|
|
|
70000
70127
|
const lineSpacing = scoreRenderer.getLineHeight(1);
|
|
70001
70128
|
const firstTopLedgerY = scoreRenderer.getLineY(-1);
|
|
70002
70129
|
const firstBottomLedgerY = scoreRenderer.getLineY(scoreRenderer.drawnLineCount);
|
|
70003
|
-
const minNoteLineY = scoreRenderer.getLineY(this.
|
|
70004
|
-
const maxNoteLineY = scoreRenderer.getLineY(this.
|
|
70130
|
+
const minNoteLineY = scoreRenderer.getLineY(this.minStepsNote.steps / 2);
|
|
70131
|
+
const maxNoteLineY = scoreRenderer.getLineY(this.maxStepsNote.steps / 2);
|
|
70005
70132
|
const lineYOffset = (this.renderer.smuflMetrics.legerLineThickness * scale) / 2;
|
|
70006
70133
|
let y = firstTopLedgerY;
|
|
70007
70134
|
while (y >= minNoteLineY) {
|
|
@@ -70024,21 +70151,87 @@
|
|
|
70024
70151
|
* @internal
|
|
70025
70152
|
*/
|
|
70026
70153
|
class TremoloPickingGlyph extends MusicFontGlyph {
|
|
70027
|
-
constructor(x, y,
|
|
70028
|
-
super(x, y, 1, TremoloPickingGlyph._getSymbol(
|
|
70154
|
+
constructor(x, y, effect) {
|
|
70155
|
+
super(x, y, 1, TremoloPickingGlyph._getSymbol(effect));
|
|
70029
70156
|
}
|
|
70030
|
-
static _getSymbol(
|
|
70031
|
-
|
|
70032
|
-
|
|
70033
|
-
|
|
70034
|
-
|
|
70035
|
-
|
|
70036
|
-
|
|
70037
|
-
|
|
70038
|
-
|
|
70039
|
-
|
|
70157
|
+
static _getSymbol(effect) {
|
|
70158
|
+
if (effect.style === TremoloPickingStyle.BuzzRoll) {
|
|
70159
|
+
return MusicFontSymbol.BuzzRoll;
|
|
70160
|
+
}
|
|
70161
|
+
else {
|
|
70162
|
+
switch (effect.marks) {
|
|
70163
|
+
case 1:
|
|
70164
|
+
return MusicFontSymbol.Tremolo1;
|
|
70165
|
+
case 2:
|
|
70166
|
+
return MusicFontSymbol.Tremolo2;
|
|
70167
|
+
case 3:
|
|
70168
|
+
return MusicFontSymbol.Tremolo3;
|
|
70169
|
+
case 4:
|
|
70170
|
+
return MusicFontSymbol.Tremolo4;
|
|
70171
|
+
case 5:
|
|
70172
|
+
return MusicFontSymbol.Tremolo5;
|
|
70173
|
+
default:
|
|
70174
|
+
return MusicFontSymbol.None;
|
|
70175
|
+
}
|
|
70040
70176
|
}
|
|
70041
70177
|
}
|
|
70178
|
+
stemExtensionHeight = 0;
|
|
70179
|
+
alignTremoloPickingGlyph(direction, flagEnd, firstNoteY, duration) {
|
|
70180
|
+
const lr = this.renderer;
|
|
70181
|
+
const smufl = lr.smuflMetrics;
|
|
70182
|
+
let tremoloY = 0;
|
|
70183
|
+
const tremoloOverlap = smufl.glyphHeights.get(MusicFontSymbol.Tremolo1) / 2;
|
|
70184
|
+
const tremoloCenterOffset = this.height / 2;
|
|
70185
|
+
// whether the center or top bar should be aligned with a staff line
|
|
70186
|
+
const forceAlignWithStaffLine = this.symbol === MusicFontSymbol.Tremolo1;
|
|
70187
|
+
const lineSpacing = lr.lineSpacing;
|
|
70188
|
+
const spacing = forceAlignWithStaffLine ? lineSpacing : lineSpacing / 2;
|
|
70189
|
+
if (direction === BeamDirection.Up) {
|
|
70190
|
+
// start at note
|
|
70191
|
+
let flagBottom = flagEnd;
|
|
70192
|
+
// to bottom of stem
|
|
70193
|
+
flagBottom += smufl.stemFlagHeight.get(duration);
|
|
70194
|
+
flagBottom -= smufl.stemFlagOffsets.get(duration);
|
|
70195
|
+
// align with closest step line
|
|
70196
|
+
tremoloY = spacing * Math.ceil(flagBottom / spacing);
|
|
70197
|
+
// ensure at least 1 staff space distance between note and tremolo bottom bar
|
|
70198
|
+
const tremoloBottomY = tremoloY + tremoloCenterOffset;
|
|
70199
|
+
const minSpacingY = firstNoteY - lineSpacing;
|
|
70200
|
+
if (minSpacingY < tremoloBottomY) {
|
|
70201
|
+
tremoloY = minSpacingY - tremoloCenterOffset;
|
|
70202
|
+
}
|
|
70203
|
+
// reserve the additional space needed in the stem height
|
|
70204
|
+
flagBottom += tremoloOverlap;
|
|
70205
|
+
const tremoloTop = tremoloY - tremoloCenterOffset;
|
|
70206
|
+
if (flagBottom > tremoloTop) {
|
|
70207
|
+
this.stemExtensionHeight = flagBottom - tremoloTop;
|
|
70208
|
+
}
|
|
70209
|
+
else {
|
|
70210
|
+
this.stemExtensionHeight = 0;
|
|
70211
|
+
}
|
|
70212
|
+
}
|
|
70213
|
+
else {
|
|
70214
|
+
// same logic as above but inverted
|
|
70215
|
+
let flagTop = flagEnd;
|
|
70216
|
+
flagTop -= smufl.stemFlagHeight.get(duration);
|
|
70217
|
+
flagTop += smufl.stemFlagOffsets.get(duration);
|
|
70218
|
+
tremoloY = spacing * Math.floor(flagTop / spacing);
|
|
70219
|
+
const tremoloTopY = tremoloY - tremoloCenterOffset;
|
|
70220
|
+
const minSpacingY = firstNoteY + lineSpacing;
|
|
70221
|
+
if (minSpacingY > tremoloTopY) {
|
|
70222
|
+
tremoloY = minSpacingY + tremoloCenterOffset;
|
|
70223
|
+
}
|
|
70224
|
+
flagTop -= tremoloOverlap;
|
|
70225
|
+
const tremoloBottom = tremoloY + tremoloCenterOffset;
|
|
70226
|
+
if (flagTop < tremoloBottom) {
|
|
70227
|
+
this.stemExtensionHeight = tremoloBottom - flagTop;
|
|
70228
|
+
}
|
|
70229
|
+
else {
|
|
70230
|
+
this.stemExtensionHeight = 0;
|
|
70231
|
+
}
|
|
70232
|
+
}
|
|
70233
|
+
this.y = tremoloY;
|
|
70234
|
+
}
|
|
70042
70235
|
}
|
|
70043
70236
|
|
|
70044
70237
|
/**
|
|
@@ -70049,6 +70242,7 @@
|
|
|
70049
70242
|
_notes = [];
|
|
70050
70243
|
_deadSlapped = null;
|
|
70051
70244
|
_tremoloPicking = null;
|
|
70245
|
+
_stemLengthExtension = 0;
|
|
70052
70246
|
aboveBeatEffects = new Map();
|
|
70053
70247
|
belowBeatEffects = new Map();
|
|
70054
70248
|
beat;
|
|
@@ -70070,7 +70264,7 @@
|
|
|
70070
70264
|
return new ScoreChordNoteHeadInfo(this.direction);
|
|
70071
70265
|
}
|
|
70072
70266
|
const staff = this.beat.voice.bar.staff;
|
|
70073
|
-
const key = `score.noteheads.${staff.track.index}.${staff.index}.${this.beat.absoluteDisplayStart}`;
|
|
70267
|
+
const key = `score.noteheads.${staff.track.index}.${staff.index}.${this.beat.voice.bar.index}.${this.beat.absoluteDisplayStart}`;
|
|
70074
70268
|
let existing = this.renderer.staff.getSharedLayoutData(key, undefined);
|
|
70075
70269
|
if (!existing) {
|
|
70076
70270
|
existing = new ScoreChordNoteHeadInfo(this.direction);
|
|
@@ -70103,19 +70297,26 @@
|
|
|
70103
70297
|
}
|
|
70104
70298
|
return 0;
|
|
70105
70299
|
}
|
|
70300
|
+
getLowestNoteY(requestedPosition) {
|
|
70301
|
+
return this.maxStepsNote ? this._internalGetNoteY(this.maxStepsNote.glyph, requestedPosition) : 0;
|
|
70302
|
+
}
|
|
70303
|
+
getHighestNoteY(requestedPosition) {
|
|
70304
|
+
return this.minStepsNote ? this._internalGetNoteY(this.minStepsNote.glyph, requestedPosition) : 0;
|
|
70305
|
+
}
|
|
70106
70306
|
_internalGetNoteY(n, requestedPosition) {
|
|
70107
70307
|
let pos = this.y + n.y;
|
|
70308
|
+
const sr = this.renderer;
|
|
70108
70309
|
const scale = this.beat.graceType !== GraceType.None ? EngravingSettings.GraceScale : 1;
|
|
70109
70310
|
switch (requestedPosition) {
|
|
70110
70311
|
case NoteYPosition.TopWithStem:
|
|
70111
70312
|
// stem start
|
|
70112
70313
|
pos -=
|
|
70113
|
-
(
|
|
70114
|
-
? this.renderer.smuflMetrics.stemUp.get(n.symbol).bottomY
|
|
70115
|
-
: 0) * scale;
|
|
70314
|
+
(sr.smuflMetrics.stemUp.has(n.symbol) ? sr.smuflMetrics.stemUp.get(n.symbol).bottomY : 0) * scale;
|
|
70116
70315
|
// stem size according to duration
|
|
70117
|
-
pos -= this.
|
|
70118
|
-
|
|
70316
|
+
pos -= sr.smuflMetrics.getStemLength(this.beat.duration, sr.hasFlag(this.beat)) * scale;
|
|
70317
|
+
pos -= this._stemLengthExtension;
|
|
70318
|
+
let topCenterY = sr.centerStaffStemY(this.direction);
|
|
70319
|
+
topCenterY -= this._stemLengthExtension;
|
|
70119
70320
|
return Math.min(topCenterY, pos);
|
|
70120
70321
|
case NoteYPosition.Top:
|
|
70121
70322
|
pos -= n.height / 2;
|
|
@@ -70131,20 +70332,20 @@
|
|
|
70131
70332
|
? this.renderer.smuflMetrics.stemDown.get(n.symbol).topY
|
|
70132
70333
|
: -this.renderer.smuflMetrics.glyphHeights.get(n.symbol) / 2) * scale;
|
|
70133
70334
|
// stem size according to duration
|
|
70134
|
-
pos += this.
|
|
70135
|
-
|
|
70335
|
+
pos += sr.smuflMetrics.getStemLength(this.beat.duration, sr.hasFlag(this.beat)) * scale;
|
|
70336
|
+
pos += this._stemLengthExtension;
|
|
70337
|
+
let bottomCenterY = sr.centerStaffStemY(this.direction);
|
|
70338
|
+
bottomCenterY += this._stemLengthExtension;
|
|
70136
70339
|
return Math.max(bottomCenterY, pos);
|
|
70137
70340
|
case NoteYPosition.StemUp:
|
|
70138
70341
|
pos -=
|
|
70139
|
-
(
|
|
70140
|
-
? this.renderer.smuflMetrics.stemUp.get(n.symbol).bottomY
|
|
70141
|
-
: 0) * scale;
|
|
70342
|
+
(sr.smuflMetrics.stemUp.has(n.symbol) ? sr.smuflMetrics.stemUp.get(n.symbol).bottomY : 0) * scale;
|
|
70142
70343
|
break;
|
|
70143
70344
|
case NoteYPosition.StemDown:
|
|
70144
70345
|
pos -=
|
|
70145
|
-
(
|
|
70146
|
-
?
|
|
70147
|
-
: -
|
|
70346
|
+
(sr.smuflMetrics.stemDown.has(n.symbol)
|
|
70347
|
+
? sr.smuflMetrics.stemDown.get(n.symbol).topY
|
|
70348
|
+
: -sr.smuflMetrics.glyphHeights.get(n.symbol) / 2) * scale;
|
|
70148
70349
|
break;
|
|
70149
70350
|
}
|
|
70150
70351
|
return pos;
|
|
@@ -70176,14 +70377,15 @@
|
|
|
70176
70377
|
}
|
|
70177
70378
|
else {
|
|
70178
70379
|
if (this.direction === BeamDirection.Up) {
|
|
70179
|
-
belowBeatEffectsY =
|
|
70380
|
+
belowBeatEffectsY =
|
|
70381
|
+
this._internalGetNoteY(this.maxStepsNote.glyph, NoteYPosition.Bottom) + effectSpacing;
|
|
70180
70382
|
aboveBeatEffectsY =
|
|
70181
|
-
this._internalGetNoteY(this.
|
|
70383
|
+
this._internalGetNoteY(this.minStepsNote.glyph, NoteYPosition.TopWithStem) - effectSpacing;
|
|
70182
70384
|
}
|
|
70183
70385
|
else {
|
|
70184
70386
|
belowBeatEffectsY =
|
|
70185
|
-
this._internalGetNoteY(this.
|
|
70186
|
-
aboveBeatEffectsY = this._internalGetNoteY(this.
|
|
70387
|
+
this._internalGetNoteY(this.maxStepsNote.glyph, NoteYPosition.BottomWithStem) + effectSpacing;
|
|
70388
|
+
aboveBeatEffectsY = this._internalGetNoteY(this.minStepsNote.glyph, NoteYPosition.Top) - effectSpacing;
|
|
70187
70389
|
}
|
|
70188
70390
|
}
|
|
70189
70391
|
let minEffectY = null;
|
|
@@ -70217,27 +70419,27 @@
|
|
|
70217
70419
|
scoreRenderer.registerBeatEffectOverflows(minEffectY, maxEffectY ?? 0);
|
|
70218
70420
|
}
|
|
70219
70421
|
if (this.beat.isTremolo && !this.beat.deadSlapped) {
|
|
70220
|
-
|
|
70221
|
-
let tremoloY = 0;
|
|
70222
|
-
if (direction === BeamDirection.Up) {
|
|
70223
|
-
const topY = this._internalGetNoteY(this.minNote.glyph, NoteYPosition.TopWithStem);
|
|
70224
|
-
const bottomY = this._internalGetNoteY(this.minNote.glyph, NoteYPosition.StemUp);
|
|
70225
|
-
tremoloY = (topY + bottomY) / 2;
|
|
70226
|
-
}
|
|
70227
|
-
else {
|
|
70228
|
-
const topY = this._internalGetNoteY(this.maxNote.glyph, NoteYPosition.StemDown);
|
|
70229
|
-
const bottomY = this._internalGetNoteY(this.maxNote.glyph, NoteYPosition.BottomWithStem);
|
|
70230
|
-
tremoloY = (topY + bottomY) / 2;
|
|
70231
|
-
}
|
|
70232
|
-
let tremoloX = this.stemX;
|
|
70233
|
-
const speed = this.beat.tremoloSpeed;
|
|
70234
|
-
if (this.beat.duration < Duration.Half) {
|
|
70235
|
-
tremoloX = this.width / 2;
|
|
70236
|
-
}
|
|
70237
|
-
this._tremoloPicking = new TremoloPickingGlyph(tremoloX, tremoloY, speed);
|
|
70422
|
+
this._tremoloPicking = new TremoloPickingGlyph(0, 0, this.beat.tremoloPicking);
|
|
70238
70423
|
this._tremoloPicking.renderer = this.renderer;
|
|
70239
70424
|
this._tremoloPicking.doLayout();
|
|
70425
|
+
this._alignTremoloPickingGlyph();
|
|
70426
|
+
}
|
|
70427
|
+
}
|
|
70428
|
+
_alignTremoloPickingGlyph() {
|
|
70429
|
+
const g = this._tremoloPicking;
|
|
70430
|
+
const direction = this.direction;
|
|
70431
|
+
if (direction === BeamDirection.Up) {
|
|
70432
|
+
g.alignTremoloPickingGlyph(direction, this.getHighestNoteY(NoteYPosition.TopWithStem), this.getHighestNoteY(NoteYPosition.Center), this.beat.duration);
|
|
70433
|
+
}
|
|
70434
|
+
else {
|
|
70435
|
+
g.alignTremoloPickingGlyph(direction, this.getLowestNoteY(NoteYPosition.BottomWithStem), this.getLowestNoteY(NoteYPosition.Center), this.beat.duration);
|
|
70436
|
+
}
|
|
70437
|
+
this._stemLengthExtension = g.stemExtensionHeight;
|
|
70438
|
+
let tremoloX = this.stemX;
|
|
70439
|
+
if (this.beat.duration < Duration.Half) {
|
|
70440
|
+
tremoloX = this.width / 2;
|
|
70240
70441
|
}
|
|
70442
|
+
g.x = tremoloX;
|
|
70241
70443
|
}
|
|
70242
70444
|
buildBoundingsLookup(beatBounds, cx, cy) {
|
|
70243
70445
|
for (const note of this._notes) {
|
|
@@ -70486,17 +70688,17 @@
|
|
|
70486
70688
|
if (!endGlyph) {
|
|
70487
70689
|
return false;
|
|
70488
70690
|
}
|
|
70489
|
-
return !!endGlyph.
|
|
70691
|
+
return !!endGlyph.minStepsNote && !!endGlyph.maxStepsNote;
|
|
70490
70692
|
}
|
|
70491
70693
|
getBoundingBoxTop() {
|
|
70492
|
-
if (this._endGlyph?.
|
|
70493
|
-
return this._endGlyph.
|
|
70694
|
+
if (this._endGlyph?.minStepsNote) {
|
|
70695
|
+
return this._endGlyph.minStepsNote.glyph.getBoundingBoxTop();
|
|
70494
70696
|
}
|
|
70495
70697
|
return super.getBoundingBoxTop();
|
|
70496
70698
|
}
|
|
70497
70699
|
getBoundingBoxBottom() {
|
|
70498
|
-
if (this._endGlyph?.
|
|
70499
|
-
return this._endGlyph.
|
|
70700
|
+
if (this._endGlyph?.maxStepsNote) {
|
|
70701
|
+
return this._endGlyph.maxStepsNote.glyph.getBoundingBoxBottom();
|
|
70500
70702
|
}
|
|
70501
70703
|
return super.getBoundingBoxBottom();
|
|
70502
70704
|
}
|
|
@@ -70729,6 +70931,89 @@
|
|
|
70729
70931
|
}
|
|
70730
70932
|
}
|
|
70731
70933
|
|
|
70934
|
+
/**
|
|
70935
|
+
* @internal
|
|
70936
|
+
*/
|
|
70937
|
+
class SlashNoteHeadGlyph extends NoteHeadGlyphBase {
|
|
70938
|
+
beatEffects = new Map();
|
|
70939
|
+
noteHeadElement = NoteSubElement.SlashNoteHead;
|
|
70940
|
+
effectElement = BeatSubElement.SlashEffects;
|
|
70941
|
+
stemX = 0;
|
|
70942
|
+
constructor(x, y, beat) {
|
|
70943
|
+
super(x, y, beat.graceType !== GraceType.None, SlashNoteHeadGlyph.getSymbol(beat.duration));
|
|
70944
|
+
this.beat = beat;
|
|
70945
|
+
}
|
|
70946
|
+
paint(cx, cy, canvas) {
|
|
70947
|
+
const _ = this.beat.notes.length === 0
|
|
70948
|
+
? undefined
|
|
70949
|
+
: ElementStyleHelper.note(canvas, this.noteHeadElement, this.beat.notes[0]);
|
|
70950
|
+
try {
|
|
70951
|
+
super.paint(cx, cy, canvas);
|
|
70952
|
+
this._paintEffects(cx, cy, canvas);
|
|
70953
|
+
}
|
|
70954
|
+
finally {
|
|
70955
|
+
_?.[Symbol.dispose]?.();
|
|
70956
|
+
}
|
|
70957
|
+
}
|
|
70958
|
+
_paintEffects(cx, cy, canvas) {
|
|
70959
|
+
const _ = ElementStyleHelper.beat(canvas, this.effectElement, this.beat);
|
|
70960
|
+
try {
|
|
70961
|
+
for (const g of this.beatEffects.values()) {
|
|
70962
|
+
g.paint(cx + this.x, cy + this.y, canvas);
|
|
70963
|
+
}
|
|
70964
|
+
}
|
|
70965
|
+
finally {
|
|
70966
|
+
_?.[Symbol.dispose]?.();
|
|
70967
|
+
}
|
|
70968
|
+
}
|
|
70969
|
+
doLayout() {
|
|
70970
|
+
super.doLayout();
|
|
70971
|
+
const lr = this.renderer;
|
|
70972
|
+
const effectSpacing = lr.smuflMetrics.onNoteEffectPadding;
|
|
70973
|
+
let effectY = lr.smuflMetrics.glyphHeights.get(this.symbol);
|
|
70974
|
+
let minEffectY = Number.NaN;
|
|
70975
|
+
let maxEffectY = Number.NaN;
|
|
70976
|
+
for (const g of this.beatEffects.values()) {
|
|
70977
|
+
g.y += effectY;
|
|
70978
|
+
g.x += this.width / 2;
|
|
70979
|
+
g.renderer = lr;
|
|
70980
|
+
effectY += g.height + effectSpacing;
|
|
70981
|
+
g.doLayout();
|
|
70982
|
+
if (Number.isNaN(minEffectY) || minEffectY > effectY) {
|
|
70983
|
+
minEffectY = effectY;
|
|
70984
|
+
}
|
|
70985
|
+
if (Number.isNaN(maxEffectY) || maxEffectY < effectY) {
|
|
70986
|
+
maxEffectY = effectY;
|
|
70987
|
+
}
|
|
70988
|
+
}
|
|
70989
|
+
if (!Number.isNaN(minEffectY)) {
|
|
70990
|
+
lr.registerBeatEffectOverflows(minEffectY, maxEffectY);
|
|
70991
|
+
}
|
|
70992
|
+
const direction = lr.getBeatDirection(this.beat);
|
|
70993
|
+
const symbol = this.symbol;
|
|
70994
|
+
if (direction === BeamDirection.Up) {
|
|
70995
|
+
const stemInfoUp = lr.smuflMetrics.stemUp.has(symbol) ? lr.smuflMetrics.stemUp.get(symbol).x : 0;
|
|
70996
|
+
this.stemX = stemInfoUp;
|
|
70997
|
+
}
|
|
70998
|
+
else {
|
|
70999
|
+
const stemInfoDown = lr.smuflMetrics.stemDown.has(symbol) ? lr.smuflMetrics.stemDown.get(symbol).x : 0;
|
|
71000
|
+
this.stemX = stemInfoDown;
|
|
71001
|
+
}
|
|
71002
|
+
}
|
|
71003
|
+
static getSymbol(duration) {
|
|
71004
|
+
switch (duration) {
|
|
71005
|
+
case Duration.QuadrupleWhole:
|
|
71006
|
+
case Duration.DoubleWhole:
|
|
71007
|
+
case Duration.Whole:
|
|
71008
|
+
return MusicFontSymbol.NoteheadSlashWhiteWhole;
|
|
71009
|
+
case Duration.Half:
|
|
71010
|
+
return MusicFontSymbol.NoteheadSlashWhiteHalf;
|
|
71011
|
+
default:
|
|
71012
|
+
return MusicFontSymbol.NoteheadSlashHorizontalEnds;
|
|
71013
|
+
}
|
|
71014
|
+
}
|
|
71015
|
+
}
|
|
71016
|
+
|
|
70732
71017
|
/**
|
|
70733
71018
|
* @internal
|
|
70734
71019
|
*/
|
|
@@ -70767,9 +71052,6 @@
|
|
|
70767
71052
|
get effectElement() {
|
|
70768
71053
|
return BeatSubElement.StandardNotationEffects;
|
|
70769
71054
|
}
|
|
70770
|
-
getNoteX(note, requestedPosition) {
|
|
70771
|
-
return this.noteHeads ? this.noteHeads.getNoteX(note, requestedPosition) : 0;
|
|
70772
|
-
}
|
|
70773
71055
|
buildBoundingsLookup(beatBounds, cx, cy) {
|
|
70774
71056
|
if (this.noteHeads) {
|
|
70775
71057
|
this.noteHeads.buildBoundingsLookup(beatBounds, cx + this.x, cy + this.y);
|
|
@@ -70801,20 +71083,34 @@
|
|
|
70801
71083
|
}
|
|
70802
71084
|
return y;
|
|
70803
71085
|
}
|
|
70804
|
-
getLowestNoteY() {
|
|
70805
|
-
|
|
71086
|
+
getLowestNoteY(requestedPosition) {
|
|
71087
|
+
// NOTE: slash handled automatically
|
|
71088
|
+
return this.noteHeads ? this.noteHeads.getLowestNoteY(requestedPosition) : 0;
|
|
70806
71089
|
}
|
|
70807
|
-
getHighestNoteY() {
|
|
70808
|
-
|
|
71090
|
+
getHighestNoteY(requestedPosition) {
|
|
71091
|
+
// NOTE: slash handled automatically
|
|
71092
|
+
return this.noteHeads ? this.noteHeads.getHighestNoteY(requestedPosition) : 0;
|
|
70809
71093
|
}
|
|
70810
71094
|
getNoteY(note, requestedPosition) {
|
|
71095
|
+
// for slashed beats always lookup first note
|
|
71096
|
+
if (note.beat.slashed) {
|
|
71097
|
+
note = note.beat.notes[0];
|
|
71098
|
+
}
|
|
70811
71099
|
return this.noteHeads ? this.noteHeads.getNoteY(note, requestedPosition) : 0;
|
|
70812
71100
|
}
|
|
71101
|
+
getNoteX(note, requestedPosition) {
|
|
71102
|
+
// for slashed beats always lookup first note
|
|
71103
|
+
if (note.beat.slashed) {
|
|
71104
|
+
note = note.beat.notes[0];
|
|
71105
|
+
}
|
|
71106
|
+
return this.noteHeads ? this.noteHeads.getNoteX(note, requestedPosition) : 0;
|
|
71107
|
+
}
|
|
70813
71108
|
getRestY(requestedPosition) {
|
|
70814
71109
|
const g = this.restGlyph;
|
|
70815
71110
|
if (g) {
|
|
70816
71111
|
switch (requestedPosition) {
|
|
70817
71112
|
case NoteYPosition.TopWithStem:
|
|
71113
|
+
return g.getBoundingBoxTop() - this.renderer.smuflMetrics.getStemLength(Duration.Quarter, true);
|
|
70818
71114
|
case NoteYPosition.Top:
|
|
70819
71115
|
return g.getBoundingBoxTop();
|
|
70820
71116
|
case NoteYPosition.Center:
|
|
@@ -70822,8 +71118,9 @@
|
|
|
70822
71118
|
case NoteYPosition.StemDown:
|
|
70823
71119
|
return g.getBoundingBoxTop() + g.height / 2;
|
|
70824
71120
|
case NoteYPosition.Bottom:
|
|
70825
|
-
case NoteYPosition.BottomWithStem:
|
|
70826
71121
|
return g.getBoundingBoxBottom();
|
|
71122
|
+
case NoteYPosition.BottomWithStem:
|
|
71123
|
+
return g.getBoundingBoxBottom() + this.renderer.smuflMetrics.getStemLength(Duration.Quarter, true);
|
|
70827
71124
|
}
|
|
70828
71125
|
}
|
|
70829
71126
|
return 0;
|
|
@@ -70906,10 +71203,18 @@
|
|
|
70906
71203
|
noteHeads.beat = this.container.beat;
|
|
70907
71204
|
const ghost = new GhostNoteContainerGlyph(false);
|
|
70908
71205
|
ghost.renderer = this.renderer;
|
|
70909
|
-
|
|
70910
|
-
|
|
70911
|
-
|
|
70912
|
-
|
|
71206
|
+
if (this.container.beat.slashed) {
|
|
71207
|
+
const steps = sr.heightLineCount - 1;
|
|
71208
|
+
const slash = new SlashNoteHeadGlyph(0, sr.getScoreY(steps), this.container.beat);
|
|
71209
|
+
slash.colorOverride = ElementStyleHelper.noteColor(sr.resources, NoteSubElement.StandardNotationNoteHead, this.container.beat.notes[0]);
|
|
71210
|
+
this.noteHeads.addMainNoteGlyph(slash, this.container.beat.notes[0], steps);
|
|
71211
|
+
}
|
|
71212
|
+
else {
|
|
71213
|
+
for (const note of this.container.beat.notes) {
|
|
71214
|
+
if (note.isVisible) {
|
|
71215
|
+
this._createNoteGlyph(note);
|
|
71216
|
+
ghost.addParenthesis(note);
|
|
71217
|
+
}
|
|
70913
71218
|
}
|
|
70914
71219
|
}
|
|
70915
71220
|
this.addNormal(noteHeads);
|
|
@@ -70938,6 +71243,24 @@
|
|
|
70938
71243
|
this.addEffect(group);
|
|
70939
71244
|
}
|
|
70940
71245
|
}
|
|
71246
|
+
if (this.renderer.bar.isMultiVoice) {
|
|
71247
|
+
let highestNotePosition = 0;
|
|
71248
|
+
let lowestNotePosition = 0;
|
|
71249
|
+
const direction = sr.getBeatDirection(this.container.beat);
|
|
71250
|
+
let offset = 0;
|
|
71251
|
+
if (this.container.beat.hasTuplet) {
|
|
71252
|
+
offset += sr.tupletOffset + sr.tupletSize;
|
|
71253
|
+
}
|
|
71254
|
+
if (direction === BeamDirection.Up) {
|
|
71255
|
+
highestNotePosition = this.getHighestNoteY(NoteYPosition.TopWithStem) - offset;
|
|
71256
|
+
lowestNotePosition = this.getLowestNoteY(NoteYPosition.Bottom);
|
|
71257
|
+
}
|
|
71258
|
+
else {
|
|
71259
|
+
highestNotePosition = this.getHighestNoteY(NoteYPosition.Top);
|
|
71260
|
+
lowestNotePosition = this.getLowestNoteY(NoteYPosition.BottomWithStem) + offset;
|
|
71261
|
+
}
|
|
71262
|
+
this.renderer.collisionHelper.reserveBeatSlot(this.container.beat, highestNotePosition, lowestNotePosition);
|
|
71263
|
+
}
|
|
70941
71264
|
}
|
|
70942
71265
|
_createRestGlyphs() {
|
|
70943
71266
|
const sr = this.renderer;
|
|
@@ -71004,9 +71327,6 @@
|
|
|
71004
71327
|
}
|
|
71005
71328
|
Logger.warning('Rendering', `No articulation found for percussion instrument ${n.percussionArticulation}`);
|
|
71006
71329
|
}
|
|
71007
|
-
if (n.beat.slashed) {
|
|
71008
|
-
return new SlashNoteHeadGlyph(0, 0, n.beat.duration, isGrace, n.beat);
|
|
71009
|
-
}
|
|
71010
71330
|
if (n.isDead) {
|
|
71011
71331
|
return new DeadNoteHeadGlyph(0, 0, isGrace);
|
|
71012
71332
|
}
|
|
@@ -71026,13 +71346,7 @@
|
|
|
71026
71346
|
const noteHeadGlyph = this._createNoteHeadGlyph(n);
|
|
71027
71347
|
noteHeadGlyph.colorOverride = ElementStyleHelper.noteColor(sr.resources, NoteSubElement.StandardNotationNoteHead, n);
|
|
71028
71348
|
// calculate y position
|
|
71029
|
-
let steps;
|
|
71030
|
-
if (n.beat.slashed) {
|
|
71031
|
-
steps = sr.heightLineCount - 1;
|
|
71032
|
-
}
|
|
71033
|
-
else {
|
|
71034
|
-
steps = sr.getNoteSteps(n);
|
|
71035
|
-
}
|
|
71349
|
+
let steps = sr.getNoteSteps(n);
|
|
71036
71350
|
noteHeadGlyph.y = sr.getScoreY(steps);
|
|
71037
71351
|
this.noteHeads.addMainNoteGlyph(noteHeadGlyph, n, steps);
|
|
71038
71352
|
if (!n.beat.slashed && n.harmonicType !== HarmonicType.None && n.harmonicType !== HarmonicType.Natural) {
|
|
@@ -71046,7 +71360,7 @@
|
|
|
71046
71360
|
}
|
|
71047
71361
|
const belowBeatEffects = this.noteHeads.belowBeatEffects;
|
|
71048
71362
|
const aboveBeatEffects = this.noteHeads.aboveBeatEffects;
|
|
71049
|
-
const outsideBeatEffects =
|
|
71363
|
+
const outsideBeatEffects = sr.getBeatDirection(this.container.beat) === BeamDirection.Up
|
|
71050
71364
|
? this.noteHeads.belowBeatEffects
|
|
71051
71365
|
: this.noteHeads.aboveBeatEffects;
|
|
71052
71366
|
if (n.isStaccato && !belowBeatEffects.has('Staccato')) {
|
|
@@ -71363,16 +71677,16 @@
|
|
|
71363
71677
|
switch (note.bendType) {
|
|
71364
71678
|
case BendType.Bend:
|
|
71365
71679
|
case BendType.PrebendBend:
|
|
71366
|
-
endY = this._endNoteGlyph.
|
|
71680
|
+
endY = this._endNoteGlyph.minStepsNote.glyph.getBoundingBoxTop();
|
|
71367
71681
|
endX = width;
|
|
71368
71682
|
break;
|
|
71369
71683
|
case BendType.BendRelease:
|
|
71370
|
-
endY = this._middleNoteGlyph.
|
|
71684
|
+
endY = this._middleNoteGlyph.minStepsNote.glyph.getBoundingBoxTop();
|
|
71371
71685
|
endX = width / 2;
|
|
71372
71686
|
break;
|
|
71373
71687
|
case BendType.Release:
|
|
71374
71688
|
case BendType.PrebendRelease:
|
|
71375
|
-
endY = this._endNoteGlyph.
|
|
71689
|
+
endY = this._endNoteGlyph.maxStepsNote.glyph.getBoundingBoxTop();
|
|
71376
71690
|
endX = width;
|
|
71377
71691
|
break;
|
|
71378
71692
|
}
|
|
@@ -72062,15 +72376,15 @@
|
|
|
72062
72376
|
const beat = this.beat;
|
|
72063
72377
|
const isGrace = beat.graceType !== GraceType.None;
|
|
72064
72378
|
if (sr.hasFlag(beat)) {
|
|
72065
|
-
const direction =
|
|
72379
|
+
const direction = sr.getBeatDirection(beat);
|
|
72066
72380
|
const scale = isGrace ? EngravingSettings.GraceScale : 1;
|
|
72067
72381
|
const symbol = FlagGlyph.getSymbol(beat.duration, direction, isGrace);
|
|
72068
|
-
const flagWidth =
|
|
72382
|
+
const flagWidth = sr.smuflMetrics.glyphWidths.get(symbol) * scale;
|
|
72069
72383
|
this._flagStretch = flagWidth;
|
|
72070
72384
|
}
|
|
72071
72385
|
else if (isGrace) {
|
|
72072
72386
|
// always use flag size as spacing on grace notes
|
|
72073
|
-
const graceSpacing =
|
|
72387
|
+
const graceSpacing = sr.smuflMetrics.glyphWidths.get(MusicFontSymbol.Flag8thUp) * EngravingSettings.GraceScale;
|
|
72074
72388
|
this._flagStretch = graceSpacing;
|
|
72075
72389
|
}
|
|
72076
72390
|
super.doLayout();
|
|
@@ -72252,73 +72566,26 @@
|
|
|
72252
72566
|
get tupletSubElement() {
|
|
72253
72567
|
return BeatSubElement.StandardNotationTuplet;
|
|
72254
72568
|
}
|
|
72255
|
-
_getSlashFlagY() {
|
|
72256
|
-
const line = (this.heightLineCount - 1) / 2;
|
|
72257
|
-
const slashY = this.getLineY(line);
|
|
72258
|
-
return slashY;
|
|
72259
|
-
}
|
|
72260
72569
|
getFlagTopY(beat, direction) {
|
|
72261
|
-
|
|
72262
|
-
|
|
72263
|
-
|
|
72264
|
-
const scale = beat.graceType !== GraceType.None ? EngravingSettings.GraceScale : 1;
|
|
72265
|
-
if (direction === BeamDirection.Down) {
|
|
72266
|
-
slashY -= this.smuflMetrics.stemDown.has(symbol)
|
|
72267
|
-
? this.smuflMetrics.stemDown.get(symbol).topY * scale
|
|
72268
|
-
: 0;
|
|
72269
|
-
}
|
|
72270
|
-
else {
|
|
72271
|
-
slashY -= this.smuflMetrics.stemUp.has(symbol)
|
|
72272
|
-
? this.smuflMetrics.stemUp.get(symbol).bottomY * scale
|
|
72273
|
-
: 0;
|
|
72274
|
-
if (!beat.isRest) {
|
|
72275
|
-
slashY -= this.smuflMetrics.standardStemLength + scale;
|
|
72276
|
-
}
|
|
72277
|
-
}
|
|
72278
|
-
return slashY;
|
|
72279
|
-
}
|
|
72280
|
-
const minNote = this.accidentalHelper.getMinStepsNote(beat);
|
|
72281
|
-
if (minNote) {
|
|
72282
|
-
return this.getNoteY(minNote, direction === BeamDirection.Up ? NoteYPosition.TopWithStem : NoteYPosition.StemDown);
|
|
72570
|
+
const position = direction === BeamDirection.Up ? NoteYPosition.TopWithStem : NoteYPosition.StemDown;
|
|
72571
|
+
if (beat.isRest) {
|
|
72572
|
+
return this.getRestY(beat, position);
|
|
72283
72573
|
}
|
|
72284
|
-
|
|
72285
|
-
|
|
72286
|
-
const scale = beat.graceType !== GraceType.None ? EngravingSettings.GraceScale : 1;
|
|
72287
|
-
y -= this.smuflMetrics.standardStemLength * scale;
|
|
72574
|
+
else {
|
|
72575
|
+
return this.voiceContainer.getHighestNoteY(beat, position);
|
|
72288
72576
|
}
|
|
72289
|
-
return y;
|
|
72290
72577
|
}
|
|
72291
72578
|
getFlagBottomY(beat, direction) {
|
|
72292
|
-
|
|
72293
|
-
|
|
72294
|
-
|
|
72295
|
-
const scale = beat.graceType !== GraceType.None ? EngravingSettings.GraceScale : 1;
|
|
72296
|
-
if (direction === BeamDirection.Down) {
|
|
72297
|
-
slashY -= this.smuflMetrics.stemDown.has(symbol)
|
|
72298
|
-
? this.smuflMetrics.stemDown.get(symbol).topY * scale
|
|
72299
|
-
: 0;
|
|
72300
|
-
slashY += this.smuflMetrics.standardStemLength + scale;
|
|
72301
|
-
}
|
|
72302
|
-
else {
|
|
72303
|
-
slashY -= this.smuflMetrics.stemUp.has(symbol)
|
|
72304
|
-
? this.smuflMetrics.stemUp.get(symbol).bottomY * scale
|
|
72305
|
-
: 0;
|
|
72306
|
-
}
|
|
72307
|
-
return slashY;
|
|
72308
|
-
}
|
|
72309
|
-
const maxNote = this.accidentalHelper.getMaxStepsNote(beat);
|
|
72310
|
-
if (maxNote) {
|
|
72311
|
-
return this.getNoteY(maxNote, direction === BeamDirection.Up ? NoteYPosition.StemUp : NoteYPosition.BottomWithStem);
|
|
72579
|
+
const position = direction === BeamDirection.Up ? NoteYPosition.StemUp : NoteYPosition.BottomWithStem;
|
|
72580
|
+
if (beat.isRest) {
|
|
72581
|
+
return this.getRestY(beat, position);
|
|
72312
72582
|
}
|
|
72313
|
-
|
|
72314
|
-
|
|
72315
|
-
const scale = beat.graceType !== GraceType.None ? EngravingSettings.GraceScale : 1;
|
|
72316
|
-
y += this.smuflMetrics.standardStemLength * scale;
|
|
72583
|
+
else {
|
|
72584
|
+
return this.voiceContainer.getLowestNoteY(beat, position);
|
|
72317
72585
|
}
|
|
72318
|
-
return y;
|
|
72319
72586
|
}
|
|
72320
72587
|
getBeamDirection(helper) {
|
|
72321
|
-
return helper.
|
|
72588
|
+
return this._beamDirections.has(helper) ? this._beamDirections.get(helper) : BeamDirection.Up;
|
|
72322
72589
|
}
|
|
72323
72590
|
centerStaffStemY(direction) {
|
|
72324
72591
|
const isStandardFive = this.bar.staff.standardNotationLineCount === Staff.DefaultStandardNotationLineCount;
|
|
@@ -72332,50 +72599,9 @@
|
|
|
72332
72599
|
}
|
|
72333
72600
|
return this.getScoreY(0);
|
|
72334
72601
|
}
|
|
72335
|
-
getStemBottomY(_beamingHelper) {
|
|
72336
|
-
throw new Error('Method not implemented.');
|
|
72337
|
-
}
|
|
72338
72602
|
get middleYPosition() {
|
|
72339
72603
|
return this.getScoreY(this.bar.staff.standardNotationLineCount - 1);
|
|
72340
72604
|
}
|
|
72341
|
-
getNoteY(note, requestedPosition) {
|
|
72342
|
-
if (note.beat.slashed) {
|
|
72343
|
-
const line = (this.heightLineCount - 1) / 2;
|
|
72344
|
-
return this.getLineY(line);
|
|
72345
|
-
}
|
|
72346
|
-
let y = super.getNoteY(note, requestedPosition);
|
|
72347
|
-
if (Number.isNaN(y)) {
|
|
72348
|
-
// NOTE: some might request the note position before the glyphs have been created
|
|
72349
|
-
// e.g. the beaming helper, for these we just need a rough
|
|
72350
|
-
// estimate on the position
|
|
72351
|
-
const steps = AccidentalHelper.computeStepsWithoutAccidentals(this.bar, note);
|
|
72352
|
-
y = this.getScoreY(steps);
|
|
72353
|
-
const scale = note.beat.graceType === GraceType.None ? 1 : EngravingSettings.GraceScale;
|
|
72354
|
-
const stemHeight = this.smuflMetrics.standardStemLength * scale;
|
|
72355
|
-
const noteHeadHeight = this.smuflMetrics.glyphHeights.get(NoteHeadGlyph.getSymbol(note.beat.duration)) * scale;
|
|
72356
|
-
switch (requestedPosition) {
|
|
72357
|
-
case NoteYPosition.TopWithStem:
|
|
72358
|
-
y -= stemHeight;
|
|
72359
|
-
break;
|
|
72360
|
-
case NoteYPosition.Top:
|
|
72361
|
-
y -= noteHeadHeight / 2;
|
|
72362
|
-
break;
|
|
72363
|
-
case NoteYPosition.Center:
|
|
72364
|
-
break;
|
|
72365
|
-
case NoteYPosition.Bottom:
|
|
72366
|
-
y += noteHeadHeight / 2;
|
|
72367
|
-
break;
|
|
72368
|
-
case NoteYPosition.BottomWithStem:
|
|
72369
|
-
y += stemHeight;
|
|
72370
|
-
break;
|
|
72371
|
-
case NoteYPosition.StemUp:
|
|
72372
|
-
break;
|
|
72373
|
-
case NoteYPosition.StemDown:
|
|
72374
|
-
break;
|
|
72375
|
-
}
|
|
72376
|
-
}
|
|
72377
|
-
return y;
|
|
72378
|
-
}
|
|
72379
72605
|
applyLayoutingInfo() {
|
|
72380
72606
|
const result = super.applyLayoutingInfo();
|
|
72381
72607
|
if (result && this.bar.isMultiVoice) {
|
|
@@ -72392,34 +72618,6 @@
|
|
|
72392
72618
|
}
|
|
72393
72619
|
return result;
|
|
72394
72620
|
}
|
|
72395
|
-
calculateBeamYWithDirection(h, x, direction) {
|
|
72396
|
-
if (h.beats.length === 0) {
|
|
72397
|
-
return direction === BeamDirection.Up
|
|
72398
|
-
? this.getFlagTopY(h.beats[0], direction)
|
|
72399
|
-
: this.getFlagBottomY(h.beats[0], direction);
|
|
72400
|
-
}
|
|
72401
|
-
this.ensureBeamDrawingInfo(h, direction);
|
|
72402
|
-
return h.drawingInfos.get(direction).calcY(x);
|
|
72403
|
-
}
|
|
72404
|
-
getBarLineStart(beat, direction) {
|
|
72405
|
-
if (beat.slashed) {
|
|
72406
|
-
return direction === BeamDirection.Down
|
|
72407
|
-
? this.getFlagTopY(beat, direction)
|
|
72408
|
-
: this.getFlagBottomY(beat, direction);
|
|
72409
|
-
}
|
|
72410
|
-
if (direction === BeamDirection.Up) {
|
|
72411
|
-
const maxNote = this.accidentalHelper.getMaxStepsNote(beat);
|
|
72412
|
-
if (maxNote) {
|
|
72413
|
-
return this.getNoteY(maxNote, NoteYPosition.StemUp);
|
|
72414
|
-
}
|
|
72415
|
-
return this.getScoreY(this.accidentalHelper.getMaxSteps(beat));
|
|
72416
|
-
}
|
|
72417
|
-
const minNote = this.accidentalHelper.getMinStepsNote(beat);
|
|
72418
|
-
if (minNote) {
|
|
72419
|
-
return this.getNoteY(minNote, NoteYPosition.StemDown);
|
|
72420
|
-
}
|
|
72421
|
-
return this.getScoreY(this.accidentalHelper.getMinSteps(beat));
|
|
72422
|
-
}
|
|
72423
72621
|
getMinLineOfBeat(beat) {
|
|
72424
72622
|
return this.accidentalHelper.getMinSteps(beat) / 2;
|
|
72425
72623
|
}
|
|
@@ -72561,27 +72759,62 @@
|
|
|
72561
72759
|
getNoteSteps(n) {
|
|
72562
72760
|
return this.accidentalHelper.getNoteSteps(n);
|
|
72563
72761
|
}
|
|
72762
|
+
_beamDirections = new Map();
|
|
72564
72763
|
completeBeamingHelper(helper) {
|
|
72565
|
-
|
|
72566
|
-
|
|
72567
|
-
|
|
72568
|
-
|
|
72569
|
-
|
|
72570
|
-
|
|
72571
|
-
|
|
72572
|
-
|
|
72573
|
-
|
|
72574
|
-
|
|
72575
|
-
|
|
72576
|
-
|
|
72577
|
-
|
|
72578
|
-
|
|
72579
|
-
|
|
72580
|
-
|
|
72581
|
-
|
|
72582
|
-
|
|
72583
|
-
|
|
72584
|
-
|
|
72764
|
+
const direction = this._calculateBeamDirection(helper);
|
|
72765
|
+
this._beamDirections.set(helper, direction);
|
|
72766
|
+
}
|
|
72767
|
+
_calculateBeamDirection(helper) {
|
|
72768
|
+
// no proper voice (should not happen usually)
|
|
72769
|
+
if (!helper.voice) {
|
|
72770
|
+
return BeamDirection.Up;
|
|
72771
|
+
}
|
|
72772
|
+
// we have a preferred direction
|
|
72773
|
+
if (helper.preferredBeamDirection !== null) {
|
|
72774
|
+
return helper.preferredBeamDirection;
|
|
72775
|
+
}
|
|
72776
|
+
// on multi-voice setups secondary voices are always down
|
|
72777
|
+
if (helper.voice.index > 0) {
|
|
72778
|
+
return this._invertBeamDirection(helper, BeamDirection.Down);
|
|
72779
|
+
}
|
|
72780
|
+
// on multi-voice setups primary voices are always up
|
|
72781
|
+
if (helper.voice.bar.isMultiVoice) {
|
|
72782
|
+
return this._invertBeamDirection(helper, BeamDirection.Up);
|
|
72783
|
+
}
|
|
72784
|
+
// grace notes are always up
|
|
72785
|
+
if (helper.beats[0].graceType !== GraceType.None) {
|
|
72786
|
+
return this._invertBeamDirection(helper, BeamDirection.Up);
|
|
72787
|
+
}
|
|
72788
|
+
if (helper.beats.length === 1 && helper.beats[0].slashed) {
|
|
72789
|
+
return this._invertBeamDirection(helper, BeamDirection.Down);
|
|
72790
|
+
}
|
|
72791
|
+
// the average line is used for determination
|
|
72792
|
+
// key lowerequal than middle line -> up
|
|
72793
|
+
// key higher than middle line -> down
|
|
72794
|
+
if (helper.highestNoteInHelper && helper.lowestNoteInHelper) {
|
|
72795
|
+
// NOTE: This is the only place where we need the locations before we have positioned the notes
|
|
72796
|
+
// TODO: we should first register all note-heads and calculate the accidentals+steps
|
|
72797
|
+
const highestNotePosition = this._getNoteCenterYBeforeLayouting(helper.highestNoteInHelper);
|
|
72798
|
+
const lowestNotePosition = this._getNoteCenterYBeforeLayouting(helper.lowestNoteInHelper);
|
|
72799
|
+
const avg = (highestNotePosition + lowestNotePosition) / 2;
|
|
72800
|
+
return this._invertBeamDirection(helper, this.middleYPosition < avg ? BeamDirection.Up : BeamDirection.Down);
|
|
72801
|
+
}
|
|
72802
|
+
return this._invertBeamDirection(helper, BeamDirection.Up);
|
|
72803
|
+
}
|
|
72804
|
+
_getNoteCenterYBeforeLayouting(note) {
|
|
72805
|
+
const steps = AccidentalHelper.computeStepsWithoutAccidentals(this.bar, note);
|
|
72806
|
+
return this.getScoreY(steps);
|
|
72807
|
+
}
|
|
72808
|
+
_invertBeamDirection(helper, direction) {
|
|
72809
|
+
if (!helper.invertBeamDirection) {
|
|
72810
|
+
return direction;
|
|
72811
|
+
}
|
|
72812
|
+
switch (direction) {
|
|
72813
|
+
case BeamDirection.Down:
|
|
72814
|
+
return BeamDirection.Up;
|
|
72815
|
+
// case BeamDirection.Up:
|
|
72816
|
+
default:
|
|
72817
|
+
return BeamDirection.Down;
|
|
72585
72818
|
}
|
|
72586
72819
|
}
|
|
72587
72820
|
paintBeamingStem(beat, _cy, x, topY, bottomY, canvas) {
|
|
@@ -72624,6 +72857,8 @@
|
|
|
72624
72857
|
* @internal
|
|
72625
72858
|
*/
|
|
72626
72859
|
class SlashBeatGlyph extends BeatOnNoteGlyphBase {
|
|
72860
|
+
_tremoloPicking;
|
|
72861
|
+
_stemLengthExtension = 0;
|
|
72627
72862
|
noteHeads = null;
|
|
72628
72863
|
deadSlapped = null;
|
|
72629
72864
|
restGlyph = null;
|
|
@@ -72666,17 +72901,18 @@
|
|
|
72666
72901
|
beatBounds.addNote(noteBounds);
|
|
72667
72902
|
}
|
|
72668
72903
|
}
|
|
72669
|
-
getLowestNoteY() {
|
|
72670
|
-
return this.
|
|
72904
|
+
getLowestNoteY(requestedPosition) {
|
|
72905
|
+
return this._internalGetNoteY(requestedPosition);
|
|
72671
72906
|
}
|
|
72672
|
-
getHighestNoteY() {
|
|
72673
|
-
return this.
|
|
72907
|
+
getHighestNoteY(requestedPosition) {
|
|
72908
|
+
return this._internalGetNoteY(requestedPosition);
|
|
72674
72909
|
}
|
|
72675
72910
|
getRestY(requestedPosition) {
|
|
72676
72911
|
const g = this.restGlyph;
|
|
72677
72912
|
if (g) {
|
|
72678
72913
|
switch (requestedPosition) {
|
|
72679
72914
|
case NoteYPosition.TopWithStem:
|
|
72915
|
+
return g.getBoundingBoxTop() - this.renderer.smuflMetrics.getStemLength(Duration.Quarter, true);
|
|
72680
72916
|
case NoteYPosition.Top:
|
|
72681
72917
|
return g.getBoundingBoxTop();
|
|
72682
72918
|
case NoteYPosition.Center:
|
|
@@ -72684,35 +72920,70 @@
|
|
|
72684
72920
|
case NoteYPosition.StemDown:
|
|
72685
72921
|
return g.getBoundingBoxTop() + g.height / 2;
|
|
72686
72922
|
case NoteYPosition.Bottom:
|
|
72687
|
-
case NoteYPosition.BottomWithStem:
|
|
72688
72923
|
return g.getBoundingBoxBottom();
|
|
72924
|
+
case NoteYPosition.BottomWithStem:
|
|
72925
|
+
return g.getBoundingBoxBottom() + this.renderer.smuflMetrics.getStemLength(Duration.Quarter, true);
|
|
72689
72926
|
}
|
|
72690
72927
|
}
|
|
72691
72928
|
return 0;
|
|
72692
72929
|
}
|
|
72693
|
-
getNoteY(
|
|
72930
|
+
getNoteY(_note, requestedPosition) {
|
|
72931
|
+
return this._internalGetNoteY(requestedPosition);
|
|
72932
|
+
}
|
|
72933
|
+
_internalGetNoteY(requestedPosition) {
|
|
72694
72934
|
let g = null;
|
|
72695
72935
|
let symbol = MusicFontSymbol.None;
|
|
72936
|
+
let hasStem = false;
|
|
72696
72937
|
if (this.noteHeads) {
|
|
72697
72938
|
g = this.noteHeads;
|
|
72698
|
-
symbol = SlashNoteHeadGlyph.getSymbol(
|
|
72939
|
+
symbol = SlashNoteHeadGlyph.getSymbol(this.container.beat.duration);
|
|
72940
|
+
hasStem = true;
|
|
72699
72941
|
}
|
|
72700
72942
|
else if (this.deadSlapped) {
|
|
72701
72943
|
g = this.deadSlapped;
|
|
72702
72944
|
}
|
|
72703
72945
|
if (g) {
|
|
72704
72946
|
let pos = this.y + g.y;
|
|
72947
|
+
const sr = this.renderer;
|
|
72948
|
+
const beat = this.container.beat;
|
|
72949
|
+
const scale = beat.graceType !== GraceType.None ? EngravingSettings.GraceScale : 1;
|
|
72705
72950
|
switch (requestedPosition) {
|
|
72706
|
-
case NoteYPosition.Top:
|
|
72707
72951
|
case NoteYPosition.TopWithStem:
|
|
72952
|
+
if (hasStem) {
|
|
72953
|
+
// stem start
|
|
72954
|
+
pos -=
|
|
72955
|
+
(sr.smuflMetrics.stemUp.has(symbol) ? sr.smuflMetrics.stemUp.get(symbol).bottomY : 0) *
|
|
72956
|
+
scale;
|
|
72957
|
+
// stem size according to duration
|
|
72958
|
+
pos -= sr.smuflMetrics.getStemLength(beat.duration, sr.hasFlag(beat)) * scale;
|
|
72959
|
+
pos -= this._stemLengthExtension;
|
|
72960
|
+
}
|
|
72961
|
+
else {
|
|
72962
|
+
pos -= g.height / 2;
|
|
72963
|
+
}
|
|
72964
|
+
return pos;
|
|
72965
|
+
case NoteYPosition.Top:
|
|
72708
72966
|
pos -= g.height / 2;
|
|
72709
72967
|
break;
|
|
72710
72968
|
case NoteYPosition.Center:
|
|
72711
72969
|
break;
|
|
72712
72970
|
case NoteYPosition.Bottom:
|
|
72713
|
-
case NoteYPosition.BottomWithStem:
|
|
72714
72971
|
pos += g.height / 2;
|
|
72715
72972
|
break;
|
|
72973
|
+
case NoteYPosition.BottomWithStem:
|
|
72974
|
+
if (hasStem) {
|
|
72975
|
+
pos -=
|
|
72976
|
+
(sr.smuflMetrics.stemDown.has(symbol)
|
|
72977
|
+
? sr.smuflMetrics.stemDown.get(symbol).topY
|
|
72978
|
+
: -sr.smuflMetrics.glyphHeights.get(symbol) / 2) * scale;
|
|
72979
|
+
// stem size according to duration
|
|
72980
|
+
pos += sr.smuflMetrics.getStemLength(beat.duration, sr.hasFlag(beat)) * scale;
|
|
72981
|
+
pos += this._stemLengthExtension;
|
|
72982
|
+
}
|
|
72983
|
+
else {
|
|
72984
|
+
pos += g.height / 2;
|
|
72985
|
+
}
|
|
72986
|
+
return pos;
|
|
72716
72987
|
case NoteYPosition.StemUp:
|
|
72717
72988
|
pos -= this.renderer.smuflMetrics.stemUp.has(symbol)
|
|
72718
72989
|
? this.renderer.smuflMetrics.stemUp.get(symbol).bottomY
|
|
@@ -72741,11 +73012,16 @@
|
|
|
72741
73012
|
}
|
|
72742
73013
|
else if (!this.container.beat.isEmpty) {
|
|
72743
73014
|
if (!this.container.beat.isRest) {
|
|
72744
|
-
const
|
|
72745
|
-
const noteHeadGlyph = new SlashNoteHeadGlyph(0, glyphY, this.container.beat.duration, isGrace, this.container.beat);
|
|
73015
|
+
const noteHeadGlyph = new SlashNoteHeadGlyph(0, glyphY, this.container.beat);
|
|
72746
73016
|
this.noteHeads = noteHeadGlyph;
|
|
72747
73017
|
noteHeadGlyph.beat = this.container.beat;
|
|
72748
73018
|
this.addNormal(noteHeadGlyph);
|
|
73019
|
+
if (this.container.beat.isTremolo) {
|
|
73020
|
+
this._tremoloPicking = new TremoloPickingGlyph(0, 0, this.container.beat.tremoloPicking);
|
|
73021
|
+
this._tremoloPicking.renderer = this.renderer;
|
|
73022
|
+
this._tremoloPicking.doLayout();
|
|
73023
|
+
this._alignTremoloPickingGlyph();
|
|
73024
|
+
}
|
|
72749
73025
|
}
|
|
72750
73026
|
else {
|
|
72751
73027
|
const restGlyph = new SlashRestGlyph(0, glyphY, this.container.beat.duration);
|
|
@@ -72780,6 +73056,27 @@
|
|
|
72780
73056
|
this.stemX = this.onTimeX;
|
|
72781
73057
|
}
|
|
72782
73058
|
this.middleX = this.onTimeX;
|
|
73059
|
+
const tremolo = this._tremoloPicking;
|
|
73060
|
+
if (tremolo) {
|
|
73061
|
+
tremolo.x = this.container.beat.duration < Duration.Half ? this.width / 2 : this.stemX;
|
|
73062
|
+
}
|
|
73063
|
+
}
|
|
73064
|
+
_alignTremoloPickingGlyph() {
|
|
73065
|
+
const g = this._tremoloPicking;
|
|
73066
|
+
g.alignTremoloPickingGlyph(BeamDirection.Up, this._internalGetNoteY(NoteYPosition.TopWithStem), this._internalGetNoteY(NoteYPosition.Center), this.container.beat.duration);
|
|
73067
|
+
this._stemLengthExtension = g.stemExtensionHeight;
|
|
73068
|
+
let tremoloX = this.stemX;
|
|
73069
|
+
if (this.container.beat.duration < Duration.Half) {
|
|
73070
|
+
tremoloX = this.width / 2;
|
|
73071
|
+
}
|
|
73072
|
+
g.x = tremoloX;
|
|
73073
|
+
}
|
|
73074
|
+
paint(cx, cy, canvas) {
|
|
73075
|
+
super.paint(cx, cy, canvas);
|
|
73076
|
+
const tremolo = this._tremoloPicking;
|
|
73077
|
+
if (tremolo) {
|
|
73078
|
+
tremolo.paint(cx + this.x, cy + this.y, canvas);
|
|
73079
|
+
}
|
|
72783
73080
|
}
|
|
72784
73081
|
}
|
|
72785
73082
|
|
|
@@ -72814,15 +73111,15 @@
|
|
|
72814
73111
|
const beat = this.beat;
|
|
72815
73112
|
const isGrace = beat.graceType !== GraceType.None;
|
|
72816
73113
|
if (sr.hasFlag(beat)) {
|
|
72817
|
-
const direction =
|
|
73114
|
+
const direction = sr.getBeatDirection(beat);
|
|
72818
73115
|
const scale = isGrace ? EngravingSettings.GraceScale : 1;
|
|
72819
73116
|
const symbol = FlagGlyph.getSymbol(beat.duration, direction, isGrace);
|
|
72820
|
-
const flagWidth =
|
|
73117
|
+
const flagWidth = sr.smuflMetrics.glyphWidths.get(symbol) * scale;
|
|
72821
73118
|
this._flagStretch = flagWidth;
|
|
72822
73119
|
}
|
|
72823
73120
|
else if (isGrace) {
|
|
72824
73121
|
// always use flag size as spacing on grace notes
|
|
72825
|
-
const graceSpacing =
|
|
73122
|
+
const graceSpacing = sr.smuflMetrics.glyphWidths.get(MusicFontSymbol.Flag8thUp) * EngravingSettings.GraceScale;
|
|
72826
73123
|
this._flagStretch = graceSpacing;
|
|
72827
73124
|
}
|
|
72828
73125
|
super.doLayout();
|
|
@@ -72909,45 +73206,26 @@
|
|
|
72909
73206
|
getNoteLine(_note) {
|
|
72910
73207
|
return 0;
|
|
72911
73208
|
}
|
|
72912
|
-
getFlagTopY(beat,
|
|
72913
|
-
|
|
72914
|
-
|
|
72915
|
-
|
|
72916
|
-
slashY -= this.smuflMetrics.stemUp.has(symbol) ? this.smuflMetrics.stemUp.get(symbol).bottomY * scale : 0;
|
|
72917
|
-
if (!beat.isRest) {
|
|
72918
|
-
slashY -= this.smuflMetrics.standardStemLength + scale;
|
|
73209
|
+
getFlagTopY(beat, direction) {
|
|
73210
|
+
const position = direction === BeamDirection.Up ? NoteYPosition.TopWithStem : NoteYPosition.StemDown;
|
|
73211
|
+
if (beat.notes.length > 0) {
|
|
73212
|
+
return this.getNoteY(beat.notes[0], position);
|
|
72919
73213
|
}
|
|
72920
|
-
|
|
72921
|
-
|
|
72922
|
-
getFlagBottomY(beat, _direction) {
|
|
72923
|
-
let slashY = this.getLineY(0);
|
|
72924
|
-
const symbol = SlashNoteHeadGlyph.getSymbol(beat.duration);
|
|
72925
|
-
const scale = beat.graceType !== GraceType.None ? EngravingSettings.GraceScale : 1;
|
|
72926
|
-
slashY -= this.smuflMetrics.stemUp.has(symbol) ? this.smuflMetrics.stemUp.get(symbol).bottomY * scale : 0;
|
|
72927
|
-
return slashY;
|
|
72928
|
-
}
|
|
72929
|
-
getBeamDirection(_helper) {
|
|
72930
|
-
return BeamDirection.Up;
|
|
72931
|
-
}
|
|
72932
|
-
getNoteY(note, requestedPosition) {
|
|
72933
|
-
let y = super.getNoteY(note, requestedPosition);
|
|
72934
|
-
if (Number.isNaN(y)) {
|
|
72935
|
-
y = this.getLineY(0);
|
|
73214
|
+
else {
|
|
73215
|
+
return this.getRestY(beat, position);
|
|
72936
73216
|
}
|
|
72937
|
-
return y;
|
|
72938
73217
|
}
|
|
72939
|
-
|
|
72940
|
-
|
|
72941
|
-
|
|
72942
|
-
|
|
72943
|
-
|
|
73218
|
+
getFlagBottomY(beat, direction) {
|
|
73219
|
+
const position = direction === BeamDirection.Up ? NoteYPosition.StemUp : NoteYPosition.BottomWithStem;
|
|
73220
|
+
if (beat.notes.length > 0) {
|
|
73221
|
+
return this.getNoteY(beat.notes[0], position);
|
|
73222
|
+
}
|
|
73223
|
+
else {
|
|
73224
|
+
return this.getRestY(beat, position);
|
|
72944
73225
|
}
|
|
72945
|
-
this.ensureBeamDrawingInfo(h, direction);
|
|
72946
|
-
return h.drawingInfos.get(direction).calcY(x);
|
|
72947
73226
|
}
|
|
72948
|
-
|
|
72949
|
-
|
|
72950
|
-
return this.getLineY(0) - noteHeadHeight / 2;
|
|
73227
|
+
getBeamDirection(_helper) {
|
|
73228
|
+
return BeamDirection.Up;
|
|
72951
73229
|
}
|
|
72952
73230
|
createLinePreBeatGlyphs() {
|
|
72953
73231
|
// Key signature
|
|
@@ -72991,6 +73269,9 @@
|
|
|
72991
73269
|
}
|
|
72992
73270
|
this.calculateBeamingOverflows(rendererTop, rendererBottom);
|
|
72993
73271
|
}
|
|
73272
|
+
shouldPaintBeamingHelper(h) {
|
|
73273
|
+
return super.shouldPaintBeamingHelper(h) && h.voice.index === 0;
|
|
73274
|
+
}
|
|
72994
73275
|
paintBeamingStem(beat, _cy, x, topY, bottomY, canvas) {
|
|
72995
73276
|
const _ = ElementStyleHelper.beat(canvas, BeatSubElement.SlashStem, beat);
|
|
72996
73277
|
try {
|
|
@@ -73037,6 +73318,15 @@
|
|
|
73037
73318
|
super(x, y);
|
|
73038
73319
|
this._note = note;
|
|
73039
73320
|
}
|
|
73321
|
+
get _padding() {
|
|
73322
|
+
return this.renderer.lineSpacing * 0.25;
|
|
73323
|
+
}
|
|
73324
|
+
getBoundingBoxTop() {
|
|
73325
|
+
return this.y - this.height / 2 - this._padding;
|
|
73326
|
+
}
|
|
73327
|
+
getBoundingBoxBottom() {
|
|
73328
|
+
return this.y + this.height / 2;
|
|
73329
|
+
}
|
|
73040
73330
|
doLayout() {
|
|
73041
73331
|
const n = this._note;
|
|
73042
73332
|
let fret = n.fret - n.beat.voice.bar.staff.transpositionPitch;
|
|
@@ -73111,11 +73401,12 @@
|
|
|
73111
73401
|
return;
|
|
73112
73402
|
}
|
|
73113
73403
|
const textWidth = this.noteStringWidth + this._trillNoteStringWidth;
|
|
73114
|
-
const x =
|
|
73115
|
-
|
|
73404
|
+
const x = cx + this.x + (this.width - textWidth) / 2;
|
|
73405
|
+
const y = cy + this.y;
|
|
73406
|
+
this.paintTrill(x, y, canvas);
|
|
73116
73407
|
const _ = ElementStyleHelper.note(canvas, NoteSubElement.GuitarTabFretNumber, this._note);
|
|
73117
73408
|
try {
|
|
73118
|
-
canvas.fillText(this._noteString, x,
|
|
73409
|
+
canvas.fillText(this._noteString, x, y);
|
|
73119
73410
|
}
|
|
73120
73411
|
finally {
|
|
73121
73412
|
_?.[Symbol.dispose]?.();
|
|
@@ -73126,7 +73417,7 @@
|
|
|
73126
73417
|
try {
|
|
73127
73418
|
const prevFont = this.renderer.scoreRenderer.canvas.font;
|
|
73128
73419
|
this.renderer.scoreRenderer.canvas.font = this.renderer.resources.graceFont;
|
|
73129
|
-
canvas.fillText(this._trillNoteString, x + this.noteStringWidth, cy
|
|
73420
|
+
canvas.fillText(this._trillNoteString, x + this.noteStringWidth, cy);
|
|
73130
73421
|
this.renderer.scoreRenderer.canvas.font = prevFont;
|
|
73131
73422
|
}
|
|
73132
73423
|
finally {
|
|
@@ -73185,11 +73476,11 @@
|
|
|
73185
73476
|
}
|
|
73186
73477
|
return 0;
|
|
73187
73478
|
}
|
|
73188
|
-
getLowestNoteY() {
|
|
73189
|
-
return this.maxStringNote ? this.getNoteY(this.maxStringNote,
|
|
73479
|
+
getLowestNoteY(requestedPosition) {
|
|
73480
|
+
return this.maxStringNote ? this.getNoteY(this.maxStringNote, requestedPosition) : 0;
|
|
73190
73481
|
}
|
|
73191
|
-
getHighestNoteY() {
|
|
73192
|
-
return this.minStringNote ? this.getNoteY(this.minStringNote,
|
|
73482
|
+
getHighestNoteY(requestedPosition) {
|
|
73483
|
+
return this.minStringNote ? this.getNoteY(this.minStringNote, requestedPosition) : 0;
|
|
73193
73484
|
}
|
|
73194
73485
|
getNoteY(note, requestedPosition) {
|
|
73195
73486
|
if (this.notesPerString.has(note.string)) {
|
|
@@ -73197,23 +73488,44 @@
|
|
|
73197
73488
|
let pos = this.y + n.y;
|
|
73198
73489
|
switch (requestedPosition) {
|
|
73199
73490
|
case NoteYPosition.Top:
|
|
73200
|
-
case NoteYPosition.TopWithStem:
|
|
73201
73491
|
pos -= n.height / 2;
|
|
73202
73492
|
break;
|
|
73493
|
+
case NoteYPosition.StemUp:
|
|
73494
|
+
pos = this.y + n.getBoundingBoxTop();
|
|
73495
|
+
break;
|
|
73203
73496
|
case NoteYPosition.Center:
|
|
73204
73497
|
break;
|
|
73205
73498
|
case NoteYPosition.Bottom:
|
|
73206
|
-
case NoteYPosition.BottomWithStem:
|
|
73207
73499
|
pos += n.height / 2;
|
|
73208
73500
|
break;
|
|
73209
|
-
case NoteYPosition.StemUp:
|
|
73210
73501
|
case NoteYPosition.StemDown:
|
|
73502
|
+
pos = this.y + n.getBoundingBoxBottom();
|
|
73503
|
+
break;
|
|
73504
|
+
case NoteYPosition.TopWithStem:
|
|
73505
|
+
pos = -this.renderer.settings.notation.rhythmHeight;
|
|
73506
|
+
pos -= this.calculateTremoloHeightForStem();
|
|
73507
|
+
break;
|
|
73508
|
+
case NoteYPosition.BottomWithStem:
|
|
73509
|
+
pos = this.renderer.height + this.renderer.settings.notation.rhythmHeight;
|
|
73510
|
+
pos += this.calculateTremoloHeightForStem();
|
|
73211
73511
|
break;
|
|
73212
73512
|
}
|
|
73213
73513
|
return pos;
|
|
73214
73514
|
}
|
|
73215
73515
|
return 0;
|
|
73216
73516
|
}
|
|
73517
|
+
calculateTremoloHeightForStem() {
|
|
73518
|
+
const beat = this.beat;
|
|
73519
|
+
if (!beat.isTremolo) {
|
|
73520
|
+
return 0;
|
|
73521
|
+
}
|
|
73522
|
+
if (beat.duration <= Duration.Quarter) {
|
|
73523
|
+
return 0;
|
|
73524
|
+
}
|
|
73525
|
+
const symbol = TremoloPickingGlyph._getSymbol(beat.tremoloPicking);
|
|
73526
|
+
const smufl = this.renderer.smuflMetrics;
|
|
73527
|
+
return smufl.glyphHeights.has(symbol) ? smufl.glyphHeights.get(symbol) : 0;
|
|
73528
|
+
}
|
|
73217
73529
|
doLayout() {
|
|
73218
73530
|
let w = 0;
|
|
73219
73531
|
if (this.beat.deadSlapped) {
|
|
@@ -73339,6 +73651,20 @@
|
|
|
73339
73651
|
return BeatSubElement.GuitarTabEffects;
|
|
73340
73652
|
}
|
|
73341
73653
|
getNoteX(note, requestedPosition) {
|
|
73654
|
+
if (this.slash) {
|
|
73655
|
+
let pos = this.slash.x;
|
|
73656
|
+
switch (requestedPosition) {
|
|
73657
|
+
case NoteXPosition.Left:
|
|
73658
|
+
break;
|
|
73659
|
+
case NoteXPosition.Center:
|
|
73660
|
+
pos += this.slash.width / 2;
|
|
73661
|
+
break;
|
|
73662
|
+
case NoteXPosition.Right:
|
|
73663
|
+
pos += this.slash.width;
|
|
73664
|
+
break;
|
|
73665
|
+
}
|
|
73666
|
+
return pos;
|
|
73667
|
+
}
|
|
73342
73668
|
return this.noteNumbers ? this.noteNumbers.getNoteX(note, requestedPosition) : 0;
|
|
73343
73669
|
}
|
|
73344
73670
|
getNoteY(note, requestedPosition) {
|
|
@@ -73349,6 +73675,7 @@
|
|
|
73349
73675
|
if (g) {
|
|
73350
73676
|
switch (requestedPosition) {
|
|
73351
73677
|
case NoteYPosition.TopWithStem:
|
|
73678
|
+
return g.getBoundingBoxTop() - this.renderer.smuflMetrics.getStemLength(Duration.Quarter, true);
|
|
73352
73679
|
case NoteYPosition.Top:
|
|
73353
73680
|
return g.getBoundingBoxTop();
|
|
73354
73681
|
case NoteYPosition.Center:
|
|
@@ -73356,17 +73683,18 @@
|
|
|
73356
73683
|
case NoteYPosition.StemDown:
|
|
73357
73684
|
return g.getBoundingBoxTop() + g.height / 2;
|
|
73358
73685
|
case NoteYPosition.Bottom:
|
|
73686
|
+
return g.getBoundingBoxTop();
|
|
73359
73687
|
case NoteYPosition.BottomWithStem:
|
|
73360
|
-
return g.getBoundingBoxBottom();
|
|
73688
|
+
return g.getBoundingBoxBottom() + this.renderer.smuflMetrics.getStemLength(Duration.Quarter, true);
|
|
73361
73689
|
}
|
|
73362
73690
|
}
|
|
73363
73691
|
return 0;
|
|
73364
73692
|
}
|
|
73365
|
-
getLowestNoteY() {
|
|
73366
|
-
return this.noteNumbers ? this.noteNumbers.getLowestNoteY() : 0;
|
|
73693
|
+
getLowestNoteY(requestedPosition) {
|
|
73694
|
+
return this.noteNumbers ? this.noteNumbers.getLowestNoteY(requestedPosition) : 0;
|
|
73367
73695
|
}
|
|
73368
|
-
getHighestNoteY() {
|
|
73369
|
-
return this.noteNumbers ? this.noteNumbers.getHighestNoteY() : 0;
|
|
73696
|
+
getHighestNoteY(requestedPosition) {
|
|
73697
|
+
return this.noteNumbers ? this.noteNumbers.getHighestNoteY(requestedPosition) : 0;
|
|
73370
73698
|
}
|
|
73371
73699
|
buildBoundingsLookup(beatBounds, cx, cy) {
|
|
73372
73700
|
if (this.noteNumbers) {
|
|
@@ -73384,7 +73712,7 @@
|
|
|
73384
73712
|
if (this.container.beat.slashed && !this.container.beat.notes.some(x => x.isTieDestination)) {
|
|
73385
73713
|
const line = Math.floor((this.renderer.bar.staff.tuning.length - 1) / 2);
|
|
73386
73714
|
const slashY = tabRenderer.getLineY(line);
|
|
73387
|
-
const slashNoteHead = new SlashNoteHeadGlyph(0, slashY, this.container.beat
|
|
73715
|
+
const slashNoteHead = new SlashNoteHeadGlyph(0, slashY, this.container.beat);
|
|
73388
73716
|
slashNoteHead.noteHeadElement = NoteSubElement.GuitarTabFretNumber;
|
|
73389
73717
|
slashNoteHead.effectElement = BeatSubElement.GuitarTabEffects;
|
|
73390
73718
|
this.slash = slashNoteHead;
|
|
@@ -73407,8 +73735,7 @@
|
|
|
73407
73735
|
//
|
|
73408
73736
|
// Tremolo Picking
|
|
73409
73737
|
if (this.container.beat.isTremolo && !beatEffects.has('tremolo')) {
|
|
73410
|
-
const
|
|
73411
|
-
const glyph = new TremoloPickingGlyph(0, 0, speed);
|
|
73738
|
+
const glyph = new TremoloPickingGlyph(0, 0, this.container.beat.tremoloPicking);
|
|
73412
73739
|
glyph.offsetY = this.renderer.smuflMetrics.glyphTop.get(glyph.symbol);
|
|
73413
73740
|
beatEffects.set('tremolo', glyph);
|
|
73414
73741
|
centeredEffectGlyphs.push(glyph);
|
|
@@ -73417,7 +73744,7 @@
|
|
|
73417
73744
|
// Note dots
|
|
73418
73745
|
//
|
|
73419
73746
|
if (this.container.beat.dots > 0 && tabRenderer.rhythmMode !== exports.TabRhythmMode.Hidden) {
|
|
73420
|
-
const y =
|
|
73747
|
+
const y = this.getNoteY(this.container.beat.maxNote, NoteYPosition.BottomWithStem);
|
|
73421
73748
|
for (let i = 0; i < this.container.beat.dots; i++) {
|
|
73422
73749
|
this.addEffect(new AugmentationDotGlyph(0, y));
|
|
73423
73750
|
}
|
|
@@ -73479,8 +73806,8 @@
|
|
|
73479
73806
|
noteNumberGlyph.renderer = this.renderer;
|
|
73480
73807
|
noteNumberGlyph.doLayout();
|
|
73481
73808
|
this.noteNumbers.addNoteGlyph(noteNumberGlyph, n);
|
|
73482
|
-
const topY = noteNumberGlyph.
|
|
73483
|
-
const bottomY =
|
|
73809
|
+
const topY = noteNumberGlyph.getBoundingBoxTop();
|
|
73810
|
+
const bottomY = noteNumberGlyph.getBoundingBoxBottom();
|
|
73484
73811
|
this.renderer.collisionHelper.reserveBeatSlot(this.container.beat, topY, bottomY);
|
|
73485
73812
|
const minString = tr.minString;
|
|
73486
73813
|
const maxString = tr.maxString;
|
|
@@ -74007,30 +74334,6 @@
|
|
|
74007
74334
|
}
|
|
74008
74335
|
}
|
|
74009
74336
|
}
|
|
74010
|
-
adjustSizes() {
|
|
74011
|
-
if (this.rhythmMode !== exports.TabRhythmMode.Hidden) {
|
|
74012
|
-
let shortestTremolo = Duration.Whole;
|
|
74013
|
-
for (const b of this.helpers.beamHelpers) {
|
|
74014
|
-
for (const h of b) {
|
|
74015
|
-
if (h.tremoloDuration && (!shortestTremolo || shortestTremolo < h.tremoloDuration)) {
|
|
74016
|
-
shortestTremolo = h.tremoloDuration;
|
|
74017
|
-
}
|
|
74018
|
-
}
|
|
74019
|
-
}
|
|
74020
|
-
switch (shortestTremolo) {
|
|
74021
|
-
case Duration.Eighth:
|
|
74022
|
-
this.height += this.smuflMetrics.glyphHeights.get(MusicFontSymbol.Tremolo1);
|
|
74023
|
-
break;
|
|
74024
|
-
case Duration.Sixteenth:
|
|
74025
|
-
this.height += this.smuflMetrics.glyphHeights.get(MusicFontSymbol.Tremolo2);
|
|
74026
|
-
break;
|
|
74027
|
-
case Duration.ThirtySecond:
|
|
74028
|
-
this.height += this.smuflMetrics.glyphHeights.get(MusicFontSymbol.Tremolo3);
|
|
74029
|
-
break;
|
|
74030
|
-
}
|
|
74031
|
-
this.registerOverflowBottom(this.settings.notation.rhythmHeight);
|
|
74032
|
-
}
|
|
74033
|
-
}
|
|
74034
74337
|
doLayout() {
|
|
74035
74338
|
const hasStandardNotation = this.bar.staff.showStandardNotation && this.scoreRenderer.layout.profile.has(ScoreBarRenderer.StaffId);
|
|
74036
74339
|
if (!hasStandardNotation) {
|
|
@@ -74111,32 +74414,29 @@
|
|
|
74111
74414
|
drawBeamHelperAsFlags(h) {
|
|
74112
74415
|
return super.drawBeamHelperAsFlags(h) || this.rhythmMode === exports.TabRhythmMode.ShowWithBeams;
|
|
74113
74416
|
}
|
|
74114
|
-
getFlagTopY(beat,
|
|
74115
|
-
const
|
|
74116
|
-
|
|
74117
|
-
|
|
74417
|
+
getFlagTopY(beat, direction) {
|
|
74418
|
+
const maxNote = beat.maxStringNote;
|
|
74419
|
+
const position = direction === BeamDirection.Up ? NoteYPosition.TopWithStem : NoteYPosition.StemDown;
|
|
74420
|
+
if (maxNote) {
|
|
74421
|
+
return this.getNoteY(maxNote, position);
|
|
74422
|
+
}
|
|
74423
|
+
else {
|
|
74424
|
+
return this.getRestY(beat, position);
|
|
74118
74425
|
}
|
|
74119
|
-
return container.getNoteY(beat.minStringNote, NoteYPosition.Bottom) + this.smuflMetrics.staffLineThickness;
|
|
74120
|
-
}
|
|
74121
|
-
getFlagBottomY(_beat, _direction) {
|
|
74122
|
-
return this.getFlagAndBarPos();
|
|
74123
|
-
}
|
|
74124
|
-
getFlagStemSize(_duration, _forceMinStem = false) {
|
|
74125
|
-
return 0; // fixed size via getFlagBottomY
|
|
74126
74426
|
}
|
|
74127
|
-
|
|
74128
|
-
|
|
74427
|
+
getFlagBottomY(beat, direction) {
|
|
74428
|
+
const maxNote = beat.minStringNote;
|
|
74429
|
+
const position = direction === BeamDirection.Up ? NoteYPosition.StemUp : NoteYPosition.BottomWithStem;
|
|
74430
|
+
if (maxNote) {
|
|
74431
|
+
return this.getNoteY(maxNote, position);
|
|
74432
|
+
}
|
|
74433
|
+
else {
|
|
74434
|
+
return this.getRestY(beat, position);
|
|
74435
|
+
}
|
|
74129
74436
|
}
|
|
74130
74437
|
getBeamDirection(_helper) {
|
|
74131
74438
|
return BeamDirection.Down;
|
|
74132
74439
|
}
|
|
74133
|
-
getFlagAndBarPos() {
|
|
74134
|
-
return this.height + this.settings.notation.rhythmHeight - (this._hasTuplets ? this.tupletSize / 2 : 0);
|
|
74135
|
-
}
|
|
74136
|
-
calculateBeamYWithDirection(_h, _x, _direction) {
|
|
74137
|
-
// currently only used for duplets
|
|
74138
|
-
return this.getFlagAndBarPos();
|
|
74139
|
-
}
|
|
74140
74440
|
shouldPaintFlag(beat) {
|
|
74141
74441
|
if (!super.shouldPaintFlag(beat)) {
|
|
74142
74442
|
return false;
|
|
@@ -74159,19 +74459,20 @@
|
|
|
74159
74459
|
holes = this.helpers.collisionHelper.reservedLayoutAreasByDisplayTime.get(beat.displayStart).slots.slice();
|
|
74160
74460
|
holes.sort((a, b) => a.topY - b.topY);
|
|
74161
74461
|
}
|
|
74162
|
-
|
|
74163
|
-
|
|
74164
|
-
|
|
74165
|
-
|
|
74166
|
-
|
|
74167
|
-
|
|
74168
|
-
|
|
74169
|
-
|
|
74170
|
-
|
|
74171
|
-
|
|
74172
|
-
|
|
74173
|
-
|
|
74174
|
-
|
|
74462
|
+
// fast path -> single note == full line
|
|
74463
|
+
if (holes.length === 1) {
|
|
74464
|
+
canvas.fillRect(x, topY, this.smuflMetrics.stemThickness, bottomY - topY);
|
|
74465
|
+
return;
|
|
74466
|
+
}
|
|
74467
|
+
const bottomYRelative = bottomY - cy;
|
|
74468
|
+
// slow path -> multiple notes == lines between notes
|
|
74469
|
+
const bottomHole = holes[holes.length - 1];
|
|
74470
|
+
canvas.fillRect(x, cy + bottomHole.bottomY, this.smuflMetrics.stemThickness, bottomYRelative - bottomHole.bottomY);
|
|
74471
|
+
for (let i = holes.length - 1; i > 0; i--) {
|
|
74472
|
+
const bottomHoleY = holes[i].topY;
|
|
74473
|
+
const topHoleY = holes[i - 1].bottomY;
|
|
74474
|
+
if (topHoleY < bottomHoleY) {
|
|
74475
|
+
canvas.fillRect(x, cy + topHoleY, this.smuflMetrics.stemThickness, bottomHoleY - topHoleY);
|
|
74175
74476
|
}
|
|
74176
74477
|
}
|
|
74177
74478
|
}
|
|
@@ -74179,6 +74480,15 @@
|
|
|
74179
74480
|
_?.[Symbol.dispose]?.();
|
|
74180
74481
|
}
|
|
74181
74482
|
}
|
|
74483
|
+
calculateOverflows(rendererTop, rendererBottom) {
|
|
74484
|
+
super.calculateOverflows(rendererTop, rendererBottom);
|
|
74485
|
+
if (this.bar.isEmpty) {
|
|
74486
|
+
return;
|
|
74487
|
+
}
|
|
74488
|
+
if (this.rhythmMode !== exports.TabRhythmMode.Hidden) {
|
|
74489
|
+
this.calculateBeamingOverflows(rendererTop, rendererBottom);
|
|
74490
|
+
}
|
|
74491
|
+
}
|
|
74182
74492
|
}
|
|
74183
74493
|
|
|
74184
74494
|
/**
|
|
@@ -76356,16 +76666,17 @@
|
|
|
76356
76666
|
beatNode.addElement('Fadding').innerText = FadeType[beat.fade];
|
|
76357
76667
|
}
|
|
76358
76668
|
if (beat.isTremolo) {
|
|
76359
|
-
switch (beat.
|
|
76360
|
-
case
|
|
76669
|
+
switch (beat.tremoloPicking.marks) {
|
|
76670
|
+
case 1:
|
|
76361
76671
|
beatNode.addElement('Tremolo').innerText = '1/2';
|
|
76362
76672
|
break;
|
|
76363
|
-
case
|
|
76673
|
+
case 2:
|
|
76364
76674
|
beatNode.addElement('Tremolo').innerText = '1/4';
|
|
76365
76675
|
break;
|
|
76366
|
-
case
|
|
76676
|
+
case 3:
|
|
76367
76677
|
beatNode.addElement('Tremolo').innerText = '1/8';
|
|
76368
76678
|
break;
|
|
76679
|
+
// NOTE: guitar pro does not support other tremolos
|
|
76369
76680
|
}
|
|
76370
76681
|
}
|
|
76371
76682
|
if (beat.hasChord) {
|
|
@@ -79362,6 +79673,8 @@
|
|
|
79362
79673
|
get TrackNamePolicy () { return TrackNamePolicy; },
|
|
79363
79674
|
TrackStyle,
|
|
79364
79675
|
get TrackSubElement () { return TrackSubElement; },
|
|
79676
|
+
TremoloPickingEffect,
|
|
79677
|
+
get TremoloPickingStyle () { return TremoloPickingStyle; },
|
|
79365
79678
|
get TripletFeel () { return TripletFeel; },
|
|
79366
79679
|
Tuning,
|
|
79367
79680
|
TupletGroup,
|