@coderline/alphatab 1.8.0-alpha.1636 → 1.8.0-alpha.1639
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/alphaTab.core.min.mjs +2 -2
- package/dist/alphaTab.core.mjs +1042 -799
- package/dist/alphaTab.d.ts +189 -2
- package/dist/alphaTab.js +1042 -799
- package/dist/alphaTab.min.js +2 -2
- package/dist/alphaTab.min.mjs +1 -1
- package/dist/alphaTab.mjs +1 -1
- package/dist/alphaTab.worker.min.mjs +1 -1
- package/dist/alphaTab.worker.mjs +1 -1
- package/dist/alphaTab.worklet.min.mjs +1 -1
- package/dist/alphaTab.worklet.mjs +1 -1
- package/package.json +3 -3
package/dist/alphaTab.core.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* alphaTab v1.8.0-alpha.
|
|
2
|
+
* alphaTab v1.8.0-alpha.1639 (develop, build 1639)
|
|
3
3
|
*
|
|
4
4
|
* Copyright © 2025, Daniel Kuschny and Contributors, All rights reserved.
|
|
5
5
|
*
|
|
@@ -203,9 +203,9 @@ class AlphaTabError extends Error {
|
|
|
203
203
|
* @internal
|
|
204
204
|
*/
|
|
205
205
|
class VersionInfo {
|
|
206
|
-
static version = '1.8.0-alpha.
|
|
207
|
-
static date = '2025-12-
|
|
208
|
-
static commit = '
|
|
206
|
+
static version = '1.8.0-alpha.1639';
|
|
207
|
+
static date = '2025-12-09T02:16:01.440Z';
|
|
208
|
+
static commit = 'af86866e4f9d89a3ccc34006d01473a549dbbe7f';
|
|
209
209
|
static print(print) {
|
|
210
210
|
print(`alphaTab ${VersionInfo.version}`);
|
|
211
211
|
print(`commit: ${VersionInfo.commit}`);
|
|
@@ -12950,25 +12950,31 @@ class Bounds {
|
|
|
12950
12950
|
/**
|
|
12951
12951
|
* Gets or sets the X-position of the rectangle within the music notation.
|
|
12952
12952
|
*/
|
|
12953
|
-
x
|
|
12953
|
+
x;
|
|
12954
12954
|
/**
|
|
12955
12955
|
* Gets or sets the Y-position of the rectangle within the music notation.
|
|
12956
12956
|
*/
|
|
12957
|
-
y
|
|
12957
|
+
y;
|
|
12958
12958
|
/**
|
|
12959
12959
|
* Gets or sets the width of the rectangle.
|
|
12960
12960
|
*/
|
|
12961
|
-
w
|
|
12961
|
+
w;
|
|
12962
12962
|
/**
|
|
12963
12963
|
* Gets or sets the height of the rectangle.
|
|
12964
12964
|
*/
|
|
12965
|
-
h
|
|
12965
|
+
h;
|
|
12966
12966
|
scaleWith(scale) {
|
|
12967
12967
|
this.x *= scale;
|
|
12968
12968
|
this.y *= scale;
|
|
12969
12969
|
this.w *= scale;
|
|
12970
12970
|
this.h *= scale;
|
|
12971
12971
|
}
|
|
12972
|
+
constructor(x = 0, y = 0, w = 0, h = 0) {
|
|
12973
|
+
this.x = x;
|
|
12974
|
+
this.y = y;
|
|
12975
|
+
this.h = h;
|
|
12976
|
+
this.w = w;
|
|
12977
|
+
}
|
|
12972
12978
|
}
|
|
12973
12979
|
|
|
12974
12980
|
/**
|
|
@@ -49454,16 +49460,6 @@ class ExternalMediaPlayer extends BackingTrackPlayer {
|
|
|
49454
49460
|
}
|
|
49455
49461
|
}
|
|
49456
49462
|
|
|
49457
|
-
/**
|
|
49458
|
-
* @internal
|
|
49459
|
-
*/
|
|
49460
|
-
class SelectionInfo {
|
|
49461
|
-
beat;
|
|
49462
|
-
bounds = null;
|
|
49463
|
-
constructor(beat) {
|
|
49464
|
-
this.beat = beat;
|
|
49465
|
-
}
|
|
49466
|
-
}
|
|
49467
49463
|
/**
|
|
49468
49464
|
* This class represents the public API of alphaTab and provides all logic to display
|
|
49469
49465
|
* a music sheet in any UI using the given {@link IUiFacade}
|
|
@@ -51563,8 +51559,8 @@ class AlphaTabApiBase {
|
|
|
51563
51559
|
}
|
|
51564
51560
|
_isBeatMouseDown = false;
|
|
51565
51561
|
_isNoteMouseDown = false;
|
|
51566
|
-
_selectionStart
|
|
51567
|
-
_selectionEnd
|
|
51562
|
+
_selectionStart;
|
|
51563
|
+
_selectionEnd;
|
|
51568
51564
|
/**
|
|
51569
51565
|
* This event is fired whenever a the user presses the mouse button on a beat.
|
|
51570
51566
|
* @eventProperty
|
|
@@ -51807,8 +51803,8 @@ class AlphaTabApiBase {
|
|
|
51807
51803
|
return;
|
|
51808
51804
|
}
|
|
51809
51805
|
if (this._hasCursor && this.settings.player.enableUserInteraction) {
|
|
51810
|
-
this._selectionStart =
|
|
51811
|
-
this._selectionEnd =
|
|
51806
|
+
this._selectionStart = { beat };
|
|
51807
|
+
this._selectionEnd = undefined;
|
|
51812
51808
|
}
|
|
51813
51809
|
this._isBeatMouseDown = true;
|
|
51814
51810
|
this.beatMouseDown.trigger(beat);
|
|
@@ -51828,7 +51824,7 @@ class AlphaTabApiBase {
|
|
|
51828
51824
|
}
|
|
51829
51825
|
if (this.settings.player.enableUserInteraction) {
|
|
51830
51826
|
if (!this._selectionEnd || this._selectionEnd.beat !== beat) {
|
|
51831
|
-
this._selectionEnd =
|
|
51827
|
+
this._selectionEnd = { beat };
|
|
51832
51828
|
this._cursorSelectRange(this._selectionStart, this._selectionEnd);
|
|
51833
51829
|
}
|
|
51834
51830
|
}
|
|
@@ -51847,45 +51843,7 @@ class AlphaTabApiBase {
|
|
|
51847
51843
|
return;
|
|
51848
51844
|
}
|
|
51849
51845
|
if (this._hasCursor && this.settings.player.enableUserInteraction) {
|
|
51850
|
-
|
|
51851
|
-
const startTick = this._tickCache?.getBeatStart(this._selectionStart.beat) ??
|
|
51852
|
-
this._selectionStart.beat.absolutePlaybackStart;
|
|
51853
|
-
const endTick = this._tickCache?.getBeatStart(this._selectionEnd.beat) ??
|
|
51854
|
-
this._selectionEnd.beat.absolutePlaybackStart;
|
|
51855
|
-
if (endTick < startTick) {
|
|
51856
|
-
const t = this._selectionStart;
|
|
51857
|
-
this._selectionStart = this._selectionEnd;
|
|
51858
|
-
this._selectionEnd = t;
|
|
51859
|
-
}
|
|
51860
|
-
}
|
|
51861
|
-
if (this._selectionStart && this._tickCache) {
|
|
51862
|
-
// get the start and stop ticks (which consider properly repeats)
|
|
51863
|
-
const tickCache = this._tickCache;
|
|
51864
|
-
const realMasterBarStart = tickCache.getMasterBarStart(this._selectionStart.beat.voice.bar.masterBar);
|
|
51865
|
-
// move to selection start
|
|
51866
|
-
this._currentBeat = null; // reset current beat so it is updating the cursor
|
|
51867
|
-
if (this._player.state === PlayerState.Paused) {
|
|
51868
|
-
this._cursorUpdateTick(this._tickCache.getBeatStart(this._selectionStart.beat), false, 1);
|
|
51869
|
-
}
|
|
51870
|
-
this.tickPosition = realMasterBarStart + this._selectionStart.beat.playbackStart;
|
|
51871
|
-
// set playback range
|
|
51872
|
-
if (this._selectionEnd && this._selectionStart.beat !== this._selectionEnd.beat) {
|
|
51873
|
-
const realMasterBarEnd = tickCache.getMasterBarStart(this._selectionEnd.beat.voice.bar.masterBar);
|
|
51874
|
-
const range = new PlaybackRange();
|
|
51875
|
-
range.startTick = realMasterBarStart + this._selectionStart.beat.playbackStart;
|
|
51876
|
-
range.endTick =
|
|
51877
|
-
realMasterBarEnd +
|
|
51878
|
-
this._selectionEnd.beat.playbackStart +
|
|
51879
|
-
this._selectionEnd.beat.playbackDuration -
|
|
51880
|
-
50;
|
|
51881
|
-
this.playbackRange = range;
|
|
51882
|
-
}
|
|
51883
|
-
else {
|
|
51884
|
-
this._selectionStart = null;
|
|
51885
|
-
this.playbackRange = null;
|
|
51886
|
-
this._cursorSelectRange(this._selectionStart, this._selectionEnd);
|
|
51887
|
-
}
|
|
51888
|
-
}
|
|
51846
|
+
this.applyPlaybackRangeFromHighlight();
|
|
51889
51847
|
}
|
|
51890
51848
|
this.beatMouseUp.trigger(beat);
|
|
51891
51849
|
this.uiFacade.triggerEvent(this.container, 'beatMouseUp', beat, originalEvent);
|
|
@@ -51907,13 +51865,13 @@ class AlphaTabApiBase {
|
|
|
51907
51865
|
const startBeat = this._tickCache.findBeat(this._trackIndexLookup, range.startTick);
|
|
51908
51866
|
const endBeat = this._tickCache.findBeat(this._trackIndexLookup, range.endTick);
|
|
51909
51867
|
if (startBeat && endBeat) {
|
|
51910
|
-
const selectionStart =
|
|
51911
|
-
const selectionEnd =
|
|
51868
|
+
const selectionStart = { beat: startBeat.beat };
|
|
51869
|
+
const selectionEnd = { beat: endBeat.beat };
|
|
51912
51870
|
this._cursorSelectRange(selectionStart, selectionEnd);
|
|
51913
51871
|
}
|
|
51914
51872
|
}
|
|
51915
51873
|
else {
|
|
51916
|
-
this._cursorSelectRange(
|
|
51874
|
+
this._cursorSelectRange(undefined, undefined);
|
|
51917
51875
|
}
|
|
51918
51876
|
}
|
|
51919
51877
|
_setupClickHandling() {
|
|
@@ -51982,24 +51940,230 @@ class AlphaTabApiBase {
|
|
|
51982
51940
|
this._cursorSelectRange(this._selectionStart, this._selectionEnd);
|
|
51983
51941
|
});
|
|
51984
51942
|
}
|
|
51943
|
+
/**
|
|
51944
|
+
* Places the highlight markers at the specified start and end-beat range.
|
|
51945
|
+
* @param startBeat The start beat where the selection should start
|
|
51946
|
+
* @param endBeat The end beat where the selection should end.
|
|
51947
|
+
*
|
|
51948
|
+
* @remarks
|
|
51949
|
+
* Unlike actually setting {@link playbackRange} this method only places the selection markers without actually
|
|
51950
|
+
* changing the playback range. This method can be used when building custom selection systems (e.g. having draggable handles).
|
|
51951
|
+
*
|
|
51952
|
+
* @category Methods - Player
|
|
51953
|
+
* @since 1.8.0
|
|
51954
|
+
*
|
|
51955
|
+
* @example
|
|
51956
|
+
* JavaScript
|
|
51957
|
+
* ```js
|
|
51958
|
+
* const api = new alphaTab.AlphaTabApi(document.querySelector('#alphaTab'));
|
|
51959
|
+
* const startBeat = api.score.tracks[0].staves[0].bars[0].voices[0].beats[0];
|
|
51960
|
+
* const endBeat = api.score.tracks[0].staves[0].bars[3].voices[0].beats[0];
|
|
51961
|
+
* api.highlightPlaybackRange(startBeat, endBeat);
|
|
51962
|
+
* ```
|
|
51963
|
+
*
|
|
51964
|
+
* @example
|
|
51965
|
+
* C#
|
|
51966
|
+
* ```cs
|
|
51967
|
+
* var api = new AlphaTabApi<MyControl>(...);
|
|
51968
|
+
* api.ChangeTrackVolume(new Track[] { api.Score.Tracks[0], api.Score.Tracks[1] }, 1.5);
|
|
51969
|
+
* api.ChangeTrackVolume(new Track[] { api.Score.Tracks[2] }, 0.5);
|
|
51970
|
+
* var startBeat = api.Score.Tracks[0].Staves[0].Bars[0].Voices[0].Beats[0];
|
|
51971
|
+
* var endBeat = api.Score.Tracks[0].Staves[0].Bars[3].Voices[0].Beats[0];
|
|
51972
|
+
* api.HighlightPlaybackRange(startBeat, endBeat);
|
|
51973
|
+
* ```
|
|
51974
|
+
*
|
|
51975
|
+
* @example
|
|
51976
|
+
* Android
|
|
51977
|
+
* ```kotlin
|
|
51978
|
+
* val api = AlphaTabApi<MyControl>(...)
|
|
51979
|
+
* val startBeat = api.score.tracks[0].staves[0].bars[0].voices[0].beats[0]
|
|
51980
|
+
* val endBeat = api.score.tracks[0].staves[0].bars[3].voices[0].beats[0]
|
|
51981
|
+
* api.highlightPlaybackRange(startBeat, endBeat)
|
|
51982
|
+
* ```
|
|
51983
|
+
*/
|
|
51984
|
+
highlightPlaybackRange(startBeat, endBeat) {
|
|
51985
|
+
this._selectionStart = { beat: startBeat };
|
|
51986
|
+
this._selectionEnd = { beat: endBeat };
|
|
51987
|
+
this._cursorSelectRange(this._selectionStart, this._selectionEnd);
|
|
51988
|
+
}
|
|
51989
|
+
/**
|
|
51990
|
+
* Applies the playback range from the currently highlighted range.
|
|
51991
|
+
*
|
|
51992
|
+
* @remarks
|
|
51993
|
+
* This method can be used when building custom selection systems (e.g. having draggable handles).
|
|
51994
|
+
*
|
|
51995
|
+
* @category Methods - Player
|
|
51996
|
+
* @since 1.8.0
|
|
51997
|
+
*
|
|
51998
|
+
* @example
|
|
51999
|
+
* JavaScript
|
|
52000
|
+
* ```js
|
|
52001
|
+
* const api = new alphaTab.AlphaTabApi(document.querySelector('#alphaTab'));
|
|
52002
|
+
* const startBeat = api.score.tracks[0].staves[0].bars[0].voices[0].beats[0];
|
|
52003
|
+
* const endBeat = api.score.tracks[0].staves[0].bars[3].voices[0].beats[0];
|
|
52004
|
+
* api.highlightPlaybackRange(startBeat, endBeat);
|
|
52005
|
+
* api.applyPlaybackRangeFromHighlight();
|
|
52006
|
+
* ```
|
|
52007
|
+
*
|
|
52008
|
+
* @example
|
|
52009
|
+
* C#
|
|
52010
|
+
* ```cs
|
|
52011
|
+
* var api = new AlphaTabApi<MyControl>(...);
|
|
52012
|
+
* api.ChangeTrackVolume(new Track[] { api.Score.Tracks[0], api.Score.Tracks[1] }, 1.5);
|
|
52013
|
+
* api.ChangeTrackVolume(new Track[] { api.Score.Tracks[2] }, 0.5);
|
|
52014
|
+
* var startBeat = api.Score.Tracks[0].Staves[0].Bars[0].Voices[0].Beats[0];
|
|
52015
|
+
* var endBeat = api.Score.Tracks[0].Staves[0].Bars[3].Voices[0].Beats[0];
|
|
52016
|
+
* api.HighlightPlaybackRange(startBeat, endBeat);
|
|
52017
|
+
* api.ApplyPlaybackRangeFromHighlight();
|
|
52018
|
+
* ```
|
|
52019
|
+
*
|
|
52020
|
+
* @example
|
|
52021
|
+
* Android
|
|
52022
|
+
* ```kotlin
|
|
52023
|
+
* val api = AlphaTabApi<MyControl>(...)
|
|
52024
|
+
* val startBeat = api.score.tracks[0].staves[0].bars[0].voices[0].beats[0]
|
|
52025
|
+
* val endBeat = api.score.tracks[0].staves[0].bars[3].voices[0].beats[0]
|
|
52026
|
+
* api.highlightPlaybackRange(startBeat, endBeat)
|
|
52027
|
+
* api.applyPlaybackRangeFromHighlight()
|
|
52028
|
+
* ```
|
|
52029
|
+
*/
|
|
52030
|
+
applyPlaybackRangeFromHighlight() {
|
|
52031
|
+
if (this._selectionEnd) {
|
|
52032
|
+
const startTick = this._tickCache?.getBeatStart(this._selectionStart.beat) ??
|
|
52033
|
+
this._selectionStart.beat.absolutePlaybackStart;
|
|
52034
|
+
const endTick = this._tickCache?.getBeatStart(this._selectionEnd.beat) ??
|
|
52035
|
+
this._selectionEnd.beat.absolutePlaybackStart;
|
|
52036
|
+
if (endTick < startTick) {
|
|
52037
|
+
const t = this._selectionStart;
|
|
52038
|
+
this._selectionStart = this._selectionEnd;
|
|
52039
|
+
this._selectionEnd = t;
|
|
52040
|
+
}
|
|
52041
|
+
}
|
|
52042
|
+
if (this._selectionStart && this._tickCache) {
|
|
52043
|
+
// get the start and stop ticks (which consider properly repeats)
|
|
52044
|
+
const tickCache = this._tickCache;
|
|
52045
|
+
const realMasterBarStart = tickCache.getMasterBarStart(this._selectionStart.beat.voice.bar.masterBar);
|
|
52046
|
+
// move to selection start
|
|
52047
|
+
this._currentBeat = null; // reset current beat so it is updating the cursor
|
|
52048
|
+
if (this._player.state === PlayerState.Paused) {
|
|
52049
|
+
this._cursorUpdateTick(this._tickCache.getBeatStart(this._selectionStart.beat), false, 1);
|
|
52050
|
+
}
|
|
52051
|
+
this.tickPosition = realMasterBarStart + this._selectionStart.beat.playbackStart;
|
|
52052
|
+
// set playback range
|
|
52053
|
+
if (this._selectionEnd && this._selectionStart.beat !== this._selectionEnd.beat) {
|
|
52054
|
+
const realMasterBarEnd = tickCache.getMasterBarStart(this._selectionEnd.beat.voice.bar.masterBar);
|
|
52055
|
+
const range = new PlaybackRange();
|
|
52056
|
+
range.startTick = realMasterBarStart + this._selectionStart.beat.playbackStart;
|
|
52057
|
+
range.endTick =
|
|
52058
|
+
realMasterBarEnd +
|
|
52059
|
+
this._selectionEnd.beat.playbackStart +
|
|
52060
|
+
this._selectionEnd.beat.playbackDuration -
|
|
52061
|
+
50;
|
|
52062
|
+
this.playbackRange = range;
|
|
52063
|
+
}
|
|
52064
|
+
else {
|
|
52065
|
+
this._selectionStart = undefined;
|
|
52066
|
+
this.playbackRange = null;
|
|
52067
|
+
this._cursorSelectRange(this._selectionStart, this._selectionEnd);
|
|
52068
|
+
}
|
|
52069
|
+
}
|
|
52070
|
+
}
|
|
52071
|
+
/**
|
|
52072
|
+
* Clears the highlight markers marking the currently selected playback range.
|
|
52073
|
+
*
|
|
52074
|
+
* @remarks
|
|
52075
|
+
* Unlike actually setting {@link playbackRange} this method only clears the selection markers without actually
|
|
52076
|
+
* changing the playback range. This method can be used when building custom selection systems (e.g. having draggable handles).
|
|
52077
|
+
*
|
|
52078
|
+
* @category Methods - Player
|
|
52079
|
+
* @since 1.8.0
|
|
52080
|
+
*
|
|
52081
|
+
* @example
|
|
52082
|
+
* JavaScript
|
|
52083
|
+
* ```js
|
|
52084
|
+
* const api = new alphaTab.AlphaTabApi(document.querySelector('#alphaTab'));
|
|
52085
|
+
* api.clearPlaybackRangeHighlight();
|
|
52086
|
+
* ```
|
|
52087
|
+
*
|
|
52088
|
+
* @example
|
|
52089
|
+
* C#
|
|
52090
|
+
* ```cs
|
|
52091
|
+
* var api = new AlphaTabApi<MyControl>(...);
|
|
52092
|
+
* api.clearPlaybackRangeHighlight();
|
|
52093
|
+
* ```
|
|
52094
|
+
*
|
|
52095
|
+
* @example
|
|
52096
|
+
* Android
|
|
52097
|
+
* ```kotlin
|
|
52098
|
+
* val api = AlphaTabApi<MyControl>(...)
|
|
52099
|
+
* api.clearPlaybackRangeHighlight()
|
|
52100
|
+
* ```
|
|
52101
|
+
*/
|
|
52102
|
+
clearPlaybackRangeHighlight() {
|
|
52103
|
+
this._cursorSelectRange(undefined, undefined);
|
|
52104
|
+
}
|
|
52105
|
+
/**
|
|
52106
|
+
* This event is fired the shown highlights for the selected playback range changes.
|
|
52107
|
+
*
|
|
52108
|
+
* @remarks
|
|
52109
|
+
* This event is fired already during selection and not only when the selection is completed.
|
|
52110
|
+
* This event can be used to place additional custom selection markers (like drag handles).
|
|
52111
|
+
*
|
|
52112
|
+
* @eventProperty
|
|
52113
|
+
* @category Events - Player
|
|
52114
|
+
* @since 1.8.0
|
|
52115
|
+
*
|
|
52116
|
+
* @example
|
|
52117
|
+
* JavaScript
|
|
52118
|
+
* ```js
|
|
52119
|
+
* const api = new alphaTab.AlphaTabApi(document.querySelector('#alphaTab'));
|
|
52120
|
+
* api.playbackRangeHighlightChanged.on(e => {
|
|
52121
|
+
* updateSelectionHandles(e);
|
|
52122
|
+
* });
|
|
52123
|
+
* ```
|
|
52124
|
+
*
|
|
52125
|
+
* @example
|
|
52126
|
+
* C#
|
|
52127
|
+
* ```cs
|
|
52128
|
+
* var api = new AlphaTabApi<MyControl>(...);
|
|
52129
|
+
* api.PlaybackRangeHighlightChanged.On(e =>
|
|
52130
|
+
* {
|
|
52131
|
+
* UpdateSelectionHandles(e);
|
|
52132
|
+
* });
|
|
52133
|
+
* ```
|
|
52134
|
+
*
|
|
52135
|
+
* @example
|
|
52136
|
+
* Android
|
|
52137
|
+
* ```kotlin
|
|
52138
|
+
* val api = AlphaTabApi<MyControl>(...)
|
|
52139
|
+
* api.playbackRangeHighlightChanged.on { e ->
|
|
52140
|
+
* updateSelectionHandles(e)
|
|
52141
|
+
* }
|
|
52142
|
+
* ```
|
|
52143
|
+
*
|
|
52144
|
+
*/
|
|
52145
|
+
playbackRangeHighlightChanged = new EventEmitterOfT();
|
|
51985
52146
|
_cursorSelectRange(startBeat, endBeat) {
|
|
51986
52147
|
const cache = this._renderer.boundsLookup;
|
|
51987
52148
|
if (!cache) {
|
|
52149
|
+
this.playbackRangeHighlightChanged.trigger({});
|
|
51988
52150
|
return;
|
|
51989
52151
|
}
|
|
51990
52152
|
const selectionWrapper = this._selectionWrapper;
|
|
51991
52153
|
if (!selectionWrapper) {
|
|
52154
|
+
this.playbackRangeHighlightChanged.trigger({});
|
|
51992
52155
|
return;
|
|
51993
52156
|
}
|
|
51994
52157
|
selectionWrapper.clear();
|
|
51995
52158
|
if (!startBeat || !endBeat || startBeat.beat === endBeat.beat) {
|
|
52159
|
+
this.playbackRangeHighlightChanged.trigger({});
|
|
51996
52160
|
return;
|
|
51997
52161
|
}
|
|
51998
52162
|
if (!startBeat.bounds) {
|
|
51999
|
-
startBeat.bounds = cache.findBeat(startBeat.beat);
|
|
52163
|
+
startBeat.bounds = cache.findBeat(startBeat.beat) ?? undefined;
|
|
52000
52164
|
}
|
|
52001
52165
|
if (!endBeat.bounds) {
|
|
52002
|
-
endBeat.bounds = cache.findBeat(endBeat.beat);
|
|
52166
|
+
endBeat.bounds = cache.findBeat(endBeat.beat) ?? undefined;
|
|
52003
52167
|
}
|
|
52004
52168
|
const startTick = this._tickCache?.getBeatStart(startBeat.beat) ?? startBeat.beat.absolutePlaybackStart;
|
|
52005
52169
|
const endTick = this._tickCache?.getBeatStart(endBeat.beat) ?? endBeat.beat.absolutePlaybackStart;
|
|
@@ -52008,7 +52172,17 @@ class AlphaTabApiBase {
|
|
|
52008
52172
|
startBeat = endBeat;
|
|
52009
52173
|
endBeat = t;
|
|
52010
52174
|
}
|
|
52011
|
-
const
|
|
52175
|
+
const eventArgs = {
|
|
52176
|
+
startBeat: startBeat.beat,
|
|
52177
|
+
startBeatBounds: startBeat.bounds,
|
|
52178
|
+
endBeat: endBeat.beat,
|
|
52179
|
+
endBeatBounds: endBeat.bounds,
|
|
52180
|
+
highlightBlocks: []
|
|
52181
|
+
};
|
|
52182
|
+
let startX = startBeat.bounds.realBounds.x;
|
|
52183
|
+
if (startBeat.beat.index === 0) {
|
|
52184
|
+
startX = startBeat.bounds.barBounds.masterBarBounds.realBounds.x;
|
|
52185
|
+
}
|
|
52012
52186
|
let endX = endBeat.bounds.realBounds.x + endBeat.bounds.realBounds.w;
|
|
52013
52187
|
if (endBeat.beat.index === endBeat.beat.voice.beats.length - 1) {
|
|
52014
52188
|
endX =
|
|
@@ -52025,18 +52199,24 @@ class AlphaTabApiBase {
|
|
|
52025
52199
|
const staffEndX = startBeat.bounds.barBounds.masterBarBounds.staffSystemBounds.visualBounds.x +
|
|
52026
52200
|
startBeat.bounds.barBounds.masterBarBounds.staffSystemBounds.visualBounds.w;
|
|
52027
52201
|
const startSelection = this.uiFacade.createSelectionElement();
|
|
52028
|
-
|
|
52202
|
+
const startSelectionBounds = new Bounds(startX, startBeat.bounds.barBounds.masterBarBounds.visualBounds.y, staffEndX - startX, startBeat.bounds.barBounds.masterBarBounds.visualBounds.h);
|
|
52203
|
+
startSelection.setBounds(startSelectionBounds.x, startSelectionBounds.y, startSelectionBounds.w, startSelectionBounds.h);
|
|
52204
|
+
eventArgs.highlightBlocks.push(startSelectionBounds);
|
|
52029
52205
|
selectionWrapper.appendChild(startSelection);
|
|
52030
52206
|
const staffStartIndex = startBeat.bounds.barBounds.masterBarBounds.staffSystemBounds.index + 1;
|
|
52031
52207
|
const staffEndIndex = endBeat.bounds.barBounds.masterBarBounds.staffSystemBounds.index;
|
|
52032
52208
|
for (let staffIndex = staffStartIndex; staffIndex < staffEndIndex; staffIndex++) {
|
|
52033
52209
|
const staffBounds = cache.staffSystems[staffIndex];
|
|
52034
52210
|
const middleSelection = this.uiFacade.createSelectionElement();
|
|
52035
|
-
|
|
52211
|
+
const middleSelectionBounds = new Bounds(staffStartX, staffBounds.visualBounds.y, staffEndX - staffStartX, staffBounds.visualBounds.h);
|
|
52212
|
+
eventArgs.highlightBlocks.push(middleSelectionBounds);
|
|
52213
|
+
middleSelection.setBounds(middleSelectionBounds.x, middleSelectionBounds.y, middleSelectionBounds.w, middleSelectionBounds.h);
|
|
52036
52214
|
selectionWrapper.appendChild(middleSelection);
|
|
52037
52215
|
}
|
|
52038
52216
|
const endSelection = this.uiFacade.createSelectionElement();
|
|
52039
|
-
|
|
52217
|
+
const endSelectionBounds = new Bounds(staffStartX, endBeat.bounds.barBounds.masterBarBounds.visualBounds.y, endX - staffStartX, endBeat.bounds.barBounds.masterBarBounds.visualBounds.h);
|
|
52218
|
+
eventArgs.highlightBlocks.push(endSelectionBounds);
|
|
52219
|
+
endSelection.setBounds(endSelectionBounds.x, endSelectionBounds.y, endSelectionBounds.w, endSelectionBounds.h);
|
|
52040
52220
|
selectionWrapper.appendChild(endSelection);
|
|
52041
52221
|
}
|
|
52042
52222
|
else {
|
|
@@ -52045,6 +52225,7 @@ class AlphaTabApiBase {
|
|
|
52045
52225
|
selection.setBounds(startX, startBeat.bounds.barBounds.masterBarBounds.visualBounds.y, endX - startX, startBeat.bounds.barBounds.masterBarBounds.visualBounds.h);
|
|
52046
52226
|
selectionWrapper.appendChild(selection);
|
|
52047
52227
|
}
|
|
52228
|
+
this.playbackRangeHighlightChanged.trigger(eventArgs);
|
|
52048
52229
|
}
|
|
52049
52230
|
/**
|
|
52050
52231
|
* This event is fired whenever a new song is loaded.
|
|
@@ -56483,12 +56664,12 @@ class GroupedEffectGlyph extends EffectGlyph {
|
|
|
56483
56664
|
this.endPosition = endPosition;
|
|
56484
56665
|
}
|
|
56485
56666
|
get isLinkedWithPrevious() {
|
|
56486
|
-
return !!this.previousGlyph && this.previousGlyph.renderer.staff
|
|
56667
|
+
return !!this.previousGlyph && this.previousGlyph.renderer.staff?.system === this.renderer.staff.system;
|
|
56487
56668
|
}
|
|
56488
56669
|
get isLinkedWithNext() {
|
|
56489
56670
|
return (!!this.nextGlyph &&
|
|
56490
56671
|
this.nextGlyph.renderer.isFinalized &&
|
|
56491
|
-
this.nextGlyph.renderer.staff
|
|
56672
|
+
this.nextGlyph.renderer.staff?.system === this.renderer.staff.system);
|
|
56492
56673
|
}
|
|
56493
56674
|
paint(cx, cy, canvas) {
|
|
56494
56675
|
// if we are linked with the previous, the first glyph of the group will also render this one.
|
|
@@ -58876,6 +59057,437 @@ class LeftToRightLayoutingGlyphGroup extends GlyphGroup {
|
|
|
58876
59057
|
}
|
|
58877
59058
|
}
|
|
58878
59059
|
|
|
59060
|
+
/**
|
|
59061
|
+
* @internal
|
|
59062
|
+
*/
|
|
59063
|
+
class TieGlyph extends Glyph {
|
|
59064
|
+
tieDirection = BeamDirection.Up;
|
|
59065
|
+
slurEffectId;
|
|
59066
|
+
isForEnd;
|
|
59067
|
+
constructor(slurEffectId, forEnd) {
|
|
59068
|
+
super(0, 0);
|
|
59069
|
+
this.slurEffectId = slurEffectId;
|
|
59070
|
+
this.isForEnd = forEnd;
|
|
59071
|
+
}
|
|
59072
|
+
_startX = 0;
|
|
59073
|
+
_startY = 0;
|
|
59074
|
+
_endX = 0;
|
|
59075
|
+
_endY = 0;
|
|
59076
|
+
_tieHeight = 0;
|
|
59077
|
+
_boundingBox;
|
|
59078
|
+
_shouldPaint = false;
|
|
59079
|
+
get checkForOverflow() {
|
|
59080
|
+
return this._shouldPaint && this._boundingBox !== undefined;
|
|
59081
|
+
}
|
|
59082
|
+
getBoundingBoxTop() {
|
|
59083
|
+
if (this._boundingBox) {
|
|
59084
|
+
return this._boundingBox.y;
|
|
59085
|
+
}
|
|
59086
|
+
return this._startY;
|
|
59087
|
+
}
|
|
59088
|
+
getBoundingBoxBottom() {
|
|
59089
|
+
if (this._boundingBox) {
|
|
59090
|
+
return this._boundingBox.y + this._boundingBox.h;
|
|
59091
|
+
}
|
|
59092
|
+
return this._startY;
|
|
59093
|
+
}
|
|
59094
|
+
doLayout() {
|
|
59095
|
+
this.width = 0;
|
|
59096
|
+
const startNoteRenderer = this.lookupStartBeatRenderer();
|
|
59097
|
+
const endNoteRenderer = this.lookupEndBeatRenderer();
|
|
59098
|
+
this._startX = 0;
|
|
59099
|
+
this._endX = 0;
|
|
59100
|
+
this._startY = 0;
|
|
59101
|
+
this._endY = 0;
|
|
59102
|
+
this.height = 0;
|
|
59103
|
+
// if we are on the tie start, we check if we
|
|
59104
|
+
// either can draw till the end note, or we just can draw till the bar end
|
|
59105
|
+
this.tieDirection = this.calculateTieDirection();
|
|
59106
|
+
const forEnd = this.isForEnd;
|
|
59107
|
+
this._shouldPaint = false;
|
|
59108
|
+
if (!forEnd) {
|
|
59109
|
+
if (startNoteRenderer !== endNoteRenderer) {
|
|
59110
|
+
this._startX = this.calculateStartX();
|
|
59111
|
+
this._startY = this.calculateStartY();
|
|
59112
|
+
if (!endNoteRenderer || startNoteRenderer.staff !== endNoteRenderer.staff) {
|
|
59113
|
+
const lastRendererInStaff = startNoteRenderer.staff.barRenderers[startNoteRenderer.staff.barRenderers.length - 1];
|
|
59114
|
+
this._endX = lastRendererInStaff.x + lastRendererInStaff.width;
|
|
59115
|
+
this._endY = this._startY;
|
|
59116
|
+
startNoteRenderer.scoreRenderer.layout.slurRegistry.startMultiSystemSlur(this);
|
|
59117
|
+
}
|
|
59118
|
+
else {
|
|
59119
|
+
this._endX = this.calculateEndX();
|
|
59120
|
+
this._endY = this.caclculateEndY();
|
|
59121
|
+
}
|
|
59122
|
+
}
|
|
59123
|
+
else {
|
|
59124
|
+
this._shouldPaint = true;
|
|
59125
|
+
this._startX = this.calculateStartX();
|
|
59126
|
+
this._endX = this.calculateEndX();
|
|
59127
|
+
this._startY = this.calculateStartY();
|
|
59128
|
+
this._endY = this.caclculateEndY();
|
|
59129
|
+
}
|
|
59130
|
+
this._shouldPaint = true;
|
|
59131
|
+
}
|
|
59132
|
+
else if (startNoteRenderer.staff !== endNoteRenderer.staff) {
|
|
59133
|
+
const firstRendererInStaff = startNoteRenderer.staff.barRenderers[0];
|
|
59134
|
+
this._startX = firstRendererInStaff.x;
|
|
59135
|
+
this._endX = this.calculateEndX();
|
|
59136
|
+
const startGlyph = startNoteRenderer.scoreRenderer.layout.slurRegistry.completeMultiSystemSlur(this);
|
|
59137
|
+
if (startGlyph) {
|
|
59138
|
+
this._startY = startGlyph.calculateMultiSystemSlurY(endNoteRenderer);
|
|
59139
|
+
}
|
|
59140
|
+
else {
|
|
59141
|
+
this._startY = this.caclculateEndY();
|
|
59142
|
+
}
|
|
59143
|
+
this._endY = this.caclculateEndY();
|
|
59144
|
+
this._shouldPaint = startNoteRenderer.staff !== endNoteRenderer.staff;
|
|
59145
|
+
}
|
|
59146
|
+
this._boundingBox = undefined;
|
|
59147
|
+
this.y = Math.min(this._startY, this._endY);
|
|
59148
|
+
if (this.shouldDrawBendSlur()) {
|
|
59149
|
+
this._tieHeight = 0; // TODO: Bend slur height to be considered?
|
|
59150
|
+
}
|
|
59151
|
+
else {
|
|
59152
|
+
this._tieHeight = this.getTieHeight(this._startX, this._startY, this._endX, this._endY);
|
|
59153
|
+
const tieBoundingBox = TieGlyph.calculateActualTieHeight(1, this._startX, this._startY, this._endX, this._endY, this.tieDirection === BeamDirection.Down, this._tieHeight, this.renderer.smuflMetrics.tieMidpointThickness);
|
|
59154
|
+
this._boundingBox = tieBoundingBox;
|
|
59155
|
+
this.height = tieBoundingBox.h;
|
|
59156
|
+
if (this.tieDirection === BeamDirection.Up) {
|
|
59157
|
+
// the tie might go above `this.y` due to its shape
|
|
59158
|
+
// here we calculate how much this is so we can consider the
|
|
59159
|
+
// respective overflow
|
|
59160
|
+
const overlap = this.y - tieBoundingBox.y;
|
|
59161
|
+
if (overlap > 0) {
|
|
59162
|
+
this.y -= overlap;
|
|
59163
|
+
}
|
|
59164
|
+
}
|
|
59165
|
+
}
|
|
59166
|
+
}
|
|
59167
|
+
paint(cx, cy, canvas) {
|
|
59168
|
+
if (!this._shouldPaint) {
|
|
59169
|
+
return;
|
|
59170
|
+
}
|
|
59171
|
+
if (this.shouldDrawBendSlur()) {
|
|
59172
|
+
TieGlyph.drawBendSlur(canvas, cx + this._startX, cy + this._startY, cx + this._endX, cy + this._endY, this.tieDirection === BeamDirection.Down, 1, this.renderer.smuflMetrics.tieHeight);
|
|
59173
|
+
}
|
|
59174
|
+
else {
|
|
59175
|
+
TieGlyph.paintTie(canvas, 1, cx + this._startX, cy + this._startY, cx + this._endX, cy + this._endY, this.tieDirection === BeamDirection.Down, this._tieHeight, this.renderer.smuflMetrics.tieMidpointThickness);
|
|
59176
|
+
}
|
|
59177
|
+
}
|
|
59178
|
+
getTieHeight(_startX, _startY, _endX, _endY) {
|
|
59179
|
+
return this.renderer.smuflMetrics.tieHeight;
|
|
59180
|
+
}
|
|
59181
|
+
calculateMultiSystemSlurY(renderer) {
|
|
59182
|
+
const startRenderer = this.lookupStartBeatRenderer();
|
|
59183
|
+
const startY = this.calculateStartY();
|
|
59184
|
+
const relY = startY - startRenderer.y;
|
|
59185
|
+
return renderer.y + relY;
|
|
59186
|
+
}
|
|
59187
|
+
shouldCreateMultiSystemSlur(renderer) {
|
|
59188
|
+
const endStaff = this.lookupEndBeatRenderer()?.staff;
|
|
59189
|
+
if (!endStaff) {
|
|
59190
|
+
return true;
|
|
59191
|
+
}
|
|
59192
|
+
return renderer.staff.system.index < endStaff.system.index;
|
|
59193
|
+
}
|
|
59194
|
+
static calculateActualTieHeight(scale, x1, y1, x2, y2, down, offset, size) {
|
|
59195
|
+
const cp = TieGlyph._computeBezierControlPoints(scale, x1, y1, x2, y2, down, offset, size);
|
|
59196
|
+
if (cp.length === 0) {
|
|
59197
|
+
return new Bounds(x1, y1, x2 - x1, y2 - y1);
|
|
59198
|
+
}
|
|
59199
|
+
// For a musical tie/slur, the extrema occur predictably near the midpoint
|
|
59200
|
+
// Evaluate at midpoint (t=0.5) and check endpoints
|
|
59201
|
+
const p0x = cp[0];
|
|
59202
|
+
const p0y = cp[1];
|
|
59203
|
+
const c1x = cp[2];
|
|
59204
|
+
const c1y = cp[3];
|
|
59205
|
+
const c2x = cp[4];
|
|
59206
|
+
const c2y = cp[5];
|
|
59207
|
+
const p1x = cp[6];
|
|
59208
|
+
const p1y = cp[7];
|
|
59209
|
+
// Evaluate at t=0.5 for midpoint
|
|
59210
|
+
const midX = 0.125 * p0x + 0.375 * c1x + 0.375 * c2x + 0.125 * p1x;
|
|
59211
|
+
const midY = 0.125 * p0y + 0.375 * c1y + 0.375 * c2y + 0.125 * p1y;
|
|
59212
|
+
// Bounds are simply min/max of start, end, and midpoint
|
|
59213
|
+
const xMin = Math.min(p0x, p1x, midX);
|
|
59214
|
+
const xMax = Math.max(p0x, p1x, midX);
|
|
59215
|
+
let yMin = Math.min(p0y, p1y, midY);
|
|
59216
|
+
let yMax = Math.max(p0y, p1y, midY);
|
|
59217
|
+
// Account for thickness of the tie/slur
|
|
59218
|
+
if (down) {
|
|
59219
|
+
yMax += size;
|
|
59220
|
+
}
|
|
59221
|
+
else {
|
|
59222
|
+
yMin -= size;
|
|
59223
|
+
}
|
|
59224
|
+
const b = new Bounds();
|
|
59225
|
+
b.x = xMin;
|
|
59226
|
+
b.y = yMin;
|
|
59227
|
+
b.w = xMax - xMin;
|
|
59228
|
+
b.h = yMax - yMin;
|
|
59229
|
+
return b;
|
|
59230
|
+
}
|
|
59231
|
+
static _computeBezierControlPoints(scale, x1, y1, x2, y2, down, offset, size) {
|
|
59232
|
+
if (x1 === x2 && y1 === y2) {
|
|
59233
|
+
return [];
|
|
59234
|
+
}
|
|
59235
|
+
// ensure endX > startX
|
|
59236
|
+
if (x2 < x1) {
|
|
59237
|
+
let t = x1;
|
|
59238
|
+
x1 = x2;
|
|
59239
|
+
x2 = t;
|
|
59240
|
+
t = y1;
|
|
59241
|
+
y1 = y2;
|
|
59242
|
+
y2 = t;
|
|
59243
|
+
}
|
|
59244
|
+
//
|
|
59245
|
+
// calculate control points
|
|
59246
|
+
//
|
|
59247
|
+
offset *= scale;
|
|
59248
|
+
size *= scale;
|
|
59249
|
+
if (down) {
|
|
59250
|
+
offset *= -1;
|
|
59251
|
+
size *= -1;
|
|
59252
|
+
}
|
|
59253
|
+
if (scale >= 1) {
|
|
59254
|
+
size *= 1.2;
|
|
59255
|
+
}
|
|
59256
|
+
// calculate control points on horizontal axis then rotate:
|
|
59257
|
+
/*
|
|
59258
|
+
cp1x/cpy1 cp2x/cpy2
|
|
59259
|
+
*----------------*
|
|
59260
|
+
/ \
|
|
59261
|
+
/ \
|
|
59262
|
+
x1/y1 * * x2/y2
|
|
59263
|
+
|
|
59264
|
+
cp3 and cp4 are simply with lower height
|
|
59265
|
+
*/
|
|
59266
|
+
const dY = y2 - y1;
|
|
59267
|
+
const dX = x2 - x1;
|
|
59268
|
+
const length = Math.sqrt(dX * dX + dY * dY);
|
|
59269
|
+
let cp1x = x1 + length * 0.25;
|
|
59270
|
+
let cp1y = y1 - offset;
|
|
59271
|
+
let cp2x = x1 + length * 0.75;
|
|
59272
|
+
let cp2y = y1 - offset;
|
|
59273
|
+
let cp3x = x1 + length * 0.75;
|
|
59274
|
+
let cp3y = y1 - offset - size;
|
|
59275
|
+
let cp4x = x1 + length * 0.25;
|
|
59276
|
+
let cp4y = y1 - offset - size;
|
|
59277
|
+
const angle = Math.atan2(dY, dX);
|
|
59278
|
+
[cp1x, cp1y] = TieGlyph._rotate(cp1x, cp1y, x1, y1, angle);
|
|
59279
|
+
[cp2x, cp2y] = TieGlyph._rotate(cp2x, cp2y, x1, y1, angle);
|
|
59280
|
+
[cp3x, cp3y] = TieGlyph._rotate(cp3x, cp3y, x1, y1, angle);
|
|
59281
|
+
[cp4x, cp4y] = TieGlyph._rotate(cp4x, cp4y, x1, y1, angle);
|
|
59282
|
+
return [x1, y1, cp1x, cp1y, cp2x, cp2y, x2, y2, cp3x, cp3y, cp4x, cp4y, x1, y1];
|
|
59283
|
+
}
|
|
59284
|
+
static _rotate(x, y, rotateX, rotateY, angle) {
|
|
59285
|
+
const dx = x - rotateX;
|
|
59286
|
+
const dy = y - rotateY;
|
|
59287
|
+
const rx = dx * Math.cos(angle) - dy * Math.sin(angle);
|
|
59288
|
+
const ry = dx * Math.sin(angle) + dy * Math.cos(angle);
|
|
59289
|
+
return [rotateX + rx, rotateY + ry];
|
|
59290
|
+
}
|
|
59291
|
+
static paintTie(canvas, scale, x1, y1, x2, y2, down /*= false*/, offset /*= 22*/, size /*= 4*/) {
|
|
59292
|
+
const cps = TieGlyph._computeBezierControlPoints(scale, x1, y1, x2, y2, down, offset, size);
|
|
59293
|
+
canvas.beginPath();
|
|
59294
|
+
canvas.moveTo(cps[0], cps[1]);
|
|
59295
|
+
canvas.bezierCurveTo(cps[2], cps[3], cps[4], cps[5], cps[6], cps[7]);
|
|
59296
|
+
canvas.bezierCurveTo(cps[8], cps[9], cps[10], cps[11], cps[12], cps[13]);
|
|
59297
|
+
canvas.closePath();
|
|
59298
|
+
canvas.fill();
|
|
59299
|
+
}
|
|
59300
|
+
static calculateBendSlurTopY(x1, y1, x2, y2, down, scale, bendSlurHeight) {
|
|
59301
|
+
let normalVectorX = y2 - y1;
|
|
59302
|
+
let normalVectorY = x2 - x1;
|
|
59303
|
+
const length = Math.sqrt(normalVectorX * normalVectorX + normalVectorY * normalVectorY);
|
|
59304
|
+
if (down) {
|
|
59305
|
+
normalVectorX *= -1;
|
|
59306
|
+
}
|
|
59307
|
+
else {
|
|
59308
|
+
normalVectorY *= -1;
|
|
59309
|
+
}
|
|
59310
|
+
// make to unit vector
|
|
59311
|
+
normalVectorX /= length;
|
|
59312
|
+
normalVectorY /= length;
|
|
59313
|
+
let offset = bendSlurHeight * scale;
|
|
59314
|
+
if (x2 - x1 < 20) {
|
|
59315
|
+
offset /= 2;
|
|
59316
|
+
}
|
|
59317
|
+
const centerY = (y2 + y1) / 2;
|
|
59318
|
+
const cp1Y = centerY + offset * normalVectorY;
|
|
59319
|
+
return cp1Y;
|
|
59320
|
+
}
|
|
59321
|
+
static drawBendSlur(canvas, x1, y1, x2, y2, down, scale, bendSlurHeight, slurText) {
|
|
59322
|
+
let normalVectorX = y2 - y1;
|
|
59323
|
+
let normalVectorY = x2 - x1;
|
|
59324
|
+
const length = Math.sqrt(normalVectorX * normalVectorX + normalVectorY * normalVectorY);
|
|
59325
|
+
if (down) {
|
|
59326
|
+
normalVectorX *= -1;
|
|
59327
|
+
}
|
|
59328
|
+
else {
|
|
59329
|
+
normalVectorY *= -1;
|
|
59330
|
+
}
|
|
59331
|
+
// make to unit vector
|
|
59332
|
+
normalVectorX /= length;
|
|
59333
|
+
normalVectorY /= length;
|
|
59334
|
+
// center of connection
|
|
59335
|
+
// TODO: should be 1/3
|
|
59336
|
+
const centerX = (x2 + x1) / 2;
|
|
59337
|
+
const centerY = (y2 + y1) / 2;
|
|
59338
|
+
let offset = bendSlurHeight * scale;
|
|
59339
|
+
if (x2 - x1 < 20) {
|
|
59340
|
+
offset /= 2;
|
|
59341
|
+
}
|
|
59342
|
+
const cp1X = centerX + offset * normalVectorX;
|
|
59343
|
+
const cp1Y = centerY + offset * normalVectorY;
|
|
59344
|
+
canvas.beginPath();
|
|
59345
|
+
canvas.moveTo(x1, y1);
|
|
59346
|
+
canvas.lineTo(cp1X, cp1Y);
|
|
59347
|
+
canvas.lineTo(x2, y2);
|
|
59348
|
+
canvas.stroke();
|
|
59349
|
+
if (slurText) {
|
|
59350
|
+
const w = canvas.measureText(slurText).width;
|
|
59351
|
+
const textOffset = down ? 0 : -canvas.font.size;
|
|
59352
|
+
canvas.fillText(slurText, cp1X - w / 2, cp1Y + textOffset);
|
|
59353
|
+
}
|
|
59354
|
+
}
|
|
59355
|
+
}
|
|
59356
|
+
/**
|
|
59357
|
+
* A common tie implementation using note details for positioning
|
|
59358
|
+
* @internal
|
|
59359
|
+
*/
|
|
59360
|
+
class NoteTieGlyph extends TieGlyph {
|
|
59361
|
+
startNote;
|
|
59362
|
+
endNote;
|
|
59363
|
+
startNoteRenderer = null;
|
|
59364
|
+
endNoteRenderer = null;
|
|
59365
|
+
constructor(slurEffectId, startNote, endNote, forEnd) {
|
|
59366
|
+
super(slurEffectId, forEnd);
|
|
59367
|
+
this.startNote = startNote;
|
|
59368
|
+
this.endNote = endNote;
|
|
59369
|
+
}
|
|
59370
|
+
get isLeftHandTap() {
|
|
59371
|
+
return this.startNote === this.endNote;
|
|
59372
|
+
}
|
|
59373
|
+
getTieHeight(startX, startY, endX, endY) {
|
|
59374
|
+
if (this.isLeftHandTap) {
|
|
59375
|
+
return this.renderer.smuflMetrics.tieHeight;
|
|
59376
|
+
}
|
|
59377
|
+
return super.getTieHeight(startX, startY, endX, endY);
|
|
59378
|
+
}
|
|
59379
|
+
calculateTieDirection() {
|
|
59380
|
+
// invert direction (if stems go up, ties go down to not cross them)
|
|
59381
|
+
switch (this.lookupStartBeatRenderer().getBeatDirection(this.startNote.beat)) {
|
|
59382
|
+
case BeamDirection.Up:
|
|
59383
|
+
return BeamDirection.Down;
|
|
59384
|
+
default:
|
|
59385
|
+
return BeamDirection.Up;
|
|
59386
|
+
}
|
|
59387
|
+
}
|
|
59388
|
+
calculateStartX() {
|
|
59389
|
+
const startNoteRenderer = this.lookupStartBeatRenderer();
|
|
59390
|
+
if (this.isLeftHandTap) {
|
|
59391
|
+
return this.calculateEndX() - startNoteRenderer.smuflMetrics.leftHandTabTieWidth;
|
|
59392
|
+
}
|
|
59393
|
+
return startNoteRenderer.x + startNoteRenderer.getNoteX(this.startNote, this.getStartNotePosition());
|
|
59394
|
+
}
|
|
59395
|
+
getStartNotePosition() {
|
|
59396
|
+
return NoteXPosition.Center;
|
|
59397
|
+
}
|
|
59398
|
+
calculateStartY() {
|
|
59399
|
+
const startNoteRenderer = this.lookupStartBeatRenderer();
|
|
59400
|
+
if (this.isLeftHandTap) {
|
|
59401
|
+
return startNoteRenderer.y + startNoteRenderer.getNoteY(this.startNote, NoteYPosition.Center);
|
|
59402
|
+
}
|
|
59403
|
+
switch (this.tieDirection) {
|
|
59404
|
+
case BeamDirection.Up:
|
|
59405
|
+
return startNoteRenderer.y + startNoteRenderer.getNoteY(this.startNote, NoteYPosition.Top);
|
|
59406
|
+
default:
|
|
59407
|
+
return startNoteRenderer.y + startNoteRenderer.getNoteY(this.startNote, NoteYPosition.Bottom);
|
|
59408
|
+
}
|
|
59409
|
+
}
|
|
59410
|
+
calculateEndX() {
|
|
59411
|
+
const endNoteRenderer = this.lookupEndBeatRenderer();
|
|
59412
|
+
if (!endNoteRenderer) {
|
|
59413
|
+
return this.calculateStartY() + this.renderer.smuflMetrics.leftHandTabTieWidth;
|
|
59414
|
+
}
|
|
59415
|
+
if (this.isLeftHandTap) {
|
|
59416
|
+
return endNoteRenderer.x + endNoteRenderer.getNoteX(this.endNote, NoteXPosition.Left);
|
|
59417
|
+
}
|
|
59418
|
+
return endNoteRenderer.x + endNoteRenderer.getNoteX(this.endNote, NoteXPosition.Center);
|
|
59419
|
+
}
|
|
59420
|
+
getEndNotePosition() {
|
|
59421
|
+
return NoteXPosition.Center;
|
|
59422
|
+
}
|
|
59423
|
+
caclculateEndY() {
|
|
59424
|
+
const endNoteRenderer = this.lookupEndBeatRenderer();
|
|
59425
|
+
if (!endNoteRenderer) {
|
|
59426
|
+
return this.calculateStartY();
|
|
59427
|
+
}
|
|
59428
|
+
if (this.isLeftHandTap) {
|
|
59429
|
+
return endNoteRenderer.y + endNoteRenderer.getNoteY(this.endNote, NoteYPosition.Center);
|
|
59430
|
+
}
|
|
59431
|
+
switch (this.tieDirection) {
|
|
59432
|
+
case BeamDirection.Up:
|
|
59433
|
+
return endNoteRenderer.y + endNoteRenderer.getNoteY(this.endNote, NoteYPosition.Top);
|
|
59434
|
+
default:
|
|
59435
|
+
return endNoteRenderer.y + endNoteRenderer.getNoteY(this.endNote, NoteYPosition.Bottom);
|
|
59436
|
+
}
|
|
59437
|
+
}
|
|
59438
|
+
lookupEndBeatRenderer() {
|
|
59439
|
+
if (!this.endNoteRenderer) {
|
|
59440
|
+
this.endNoteRenderer = this.renderer.scoreRenderer.layout.getRendererForBar(this.renderer.staff.staffId, this.endNote.beat.voice.bar);
|
|
59441
|
+
}
|
|
59442
|
+
return this.endNoteRenderer;
|
|
59443
|
+
}
|
|
59444
|
+
lookupStartBeatRenderer() {
|
|
59445
|
+
if (!this.startNoteRenderer) {
|
|
59446
|
+
this.startNoteRenderer = this.renderer.scoreRenderer.layout.getRendererForBar(this.renderer.staff.staffId, this.startNote.beat.voice.bar);
|
|
59447
|
+
}
|
|
59448
|
+
return this.startNoteRenderer;
|
|
59449
|
+
}
|
|
59450
|
+
shouldDrawBendSlur() {
|
|
59451
|
+
return false;
|
|
59452
|
+
}
|
|
59453
|
+
}
|
|
59454
|
+
/**
|
|
59455
|
+
* A tie glyph for continued multi-system ties/slurs
|
|
59456
|
+
* @internal
|
|
59457
|
+
*/
|
|
59458
|
+
class ContinuationTieGlyph extends TieGlyph {
|
|
59459
|
+
_startTie;
|
|
59460
|
+
constructor(startTie) {
|
|
59461
|
+
super(startTie.slurEffectId, false);
|
|
59462
|
+
this._startTie = startTie;
|
|
59463
|
+
}
|
|
59464
|
+
lookupStartBeatRenderer() {
|
|
59465
|
+
return this.renderer;
|
|
59466
|
+
}
|
|
59467
|
+
lookupEndBeatRenderer() {
|
|
59468
|
+
return this.renderer;
|
|
59469
|
+
}
|
|
59470
|
+
shouldDrawBendSlur() {
|
|
59471
|
+
return false;
|
|
59472
|
+
}
|
|
59473
|
+
calculateTieDirection() {
|
|
59474
|
+
return this._startTie.tieDirection;
|
|
59475
|
+
}
|
|
59476
|
+
calculateStartY() {
|
|
59477
|
+
return this._startTie.calculateMultiSystemSlurY(this.renderer);
|
|
59478
|
+
}
|
|
59479
|
+
caclculateEndY() {
|
|
59480
|
+
return this.calculateStartY();
|
|
59481
|
+
}
|
|
59482
|
+
calculateStartX() {
|
|
59483
|
+
return this.renderer.staff.barRenderers[0].x;
|
|
59484
|
+
}
|
|
59485
|
+
calculateEndX() {
|
|
59486
|
+
const last = this.renderer.staff.barRenderers[this.renderer.staff.barRenderers.length - 1];
|
|
59487
|
+
return last.x + last.width;
|
|
59488
|
+
}
|
|
59489
|
+
}
|
|
59490
|
+
|
|
58879
59491
|
/**
|
|
58880
59492
|
* This glyph acts as container for handling
|
|
58881
59493
|
* multiple voice rendering
|
|
@@ -59346,6 +59958,63 @@ class TuningGlyph extends GlyphGroup {
|
|
|
59346
59958
|
}
|
|
59347
59959
|
}
|
|
59348
59960
|
|
|
59961
|
+
/**
|
|
59962
|
+
* This registry keeps track of which slurs and ties were started and needs completion.
|
|
59963
|
+
* Slurs might span multiple systems, and in such cases we need to create additional
|
|
59964
|
+
* slur/ties in the intermediate and end system.
|
|
59965
|
+
*
|
|
59966
|
+
* @internal
|
|
59967
|
+
*
|
|
59968
|
+
*/
|
|
59969
|
+
class SlurRegistry {
|
|
59970
|
+
_staffLookup = new Map();
|
|
59971
|
+
clear() {
|
|
59972
|
+
this._staffLookup.clear();
|
|
59973
|
+
}
|
|
59974
|
+
startMultiSystemSlur(startGlyph) {
|
|
59975
|
+
const staffId = SlurRegistry._staffId(startGlyph.renderer.staff);
|
|
59976
|
+
let container;
|
|
59977
|
+
if (!this._staffLookup.has(staffId)) {
|
|
59978
|
+
container = {
|
|
59979
|
+
startedSlurs: new Map()
|
|
59980
|
+
};
|
|
59981
|
+
this._staffLookup.set(staffId, container);
|
|
59982
|
+
}
|
|
59983
|
+
else {
|
|
59984
|
+
container = this._staffLookup.get(staffId);
|
|
59985
|
+
}
|
|
59986
|
+
container.startedSlurs.set(startGlyph.slurEffectId, { startGlyph });
|
|
59987
|
+
}
|
|
59988
|
+
static _staffId(staff) {
|
|
59989
|
+
return `${staff.modelStaff.index}.${staff.modelStaff.track.index}.${staff.staffId}`;
|
|
59990
|
+
}
|
|
59991
|
+
completeMultiSystemSlur(endGlyph) {
|
|
59992
|
+
const staffId = SlurRegistry._staffId(endGlyph.renderer.staff);
|
|
59993
|
+
if (!this._staffLookup.has(staffId)) {
|
|
59994
|
+
return undefined;
|
|
59995
|
+
}
|
|
59996
|
+
const container = this._staffLookup.get(staffId);
|
|
59997
|
+
if (container.startedSlurs.has(endGlyph.slurEffectId)) {
|
|
59998
|
+
const info = container.startedSlurs.get(endGlyph.slurEffectId);
|
|
59999
|
+
info.endGlyph = endGlyph;
|
|
60000
|
+
return info.startGlyph;
|
|
60001
|
+
}
|
|
60002
|
+
return undefined;
|
|
60003
|
+
}
|
|
60004
|
+
*getAllContinuations(renderer) {
|
|
60005
|
+
const staffId = SlurRegistry._staffId(renderer.staff);
|
|
60006
|
+
if (!this._staffLookup.has(staffId) || renderer.index > 0) {
|
|
60007
|
+
return;
|
|
60008
|
+
}
|
|
60009
|
+
const container = this._staffLookup.get(staffId);
|
|
60010
|
+
for (const g of container.startedSlurs.values()) {
|
|
60011
|
+
if (g.startGlyph.shouldCreateMultiSystemSlur(renderer)) {
|
|
60012
|
+
yield g.startGlyph;
|
|
60013
|
+
}
|
|
60014
|
+
}
|
|
60015
|
+
}
|
|
60016
|
+
}
|
|
60017
|
+
|
|
59349
60018
|
/**
|
|
59350
60019
|
* A Staff represents a single line within a StaffSystem.
|
|
59351
60020
|
* It stores BarRenderer instances created from a given factory.
|
|
@@ -59467,7 +60136,6 @@ class RenderStaff {
|
|
|
59467
60136
|
this._sharedLayoutData = new Map();
|
|
59468
60137
|
const lastBar = this.barRenderers[this.barRenderers.length - 1];
|
|
59469
60138
|
this.barRenderers.splice(this.barRenderers.length - 1, 1);
|
|
59470
|
-
this.system.layout.unregisterBarRenderer(this.staffId, lastBar);
|
|
59471
60139
|
this.topOverflow = 0;
|
|
59472
60140
|
this.bottomOverflow = 0;
|
|
59473
60141
|
for (const r of this.barRenderers) {
|
|
@@ -59560,23 +60228,23 @@ class RenderStaff {
|
|
|
59560
60228
|
// changes in the overflows
|
|
59561
60229
|
let needsSecondPass = false;
|
|
59562
60230
|
let topOverflow = this.topOverflow;
|
|
59563
|
-
for (
|
|
59564
|
-
this.
|
|
59565
|
-
if (
|
|
60231
|
+
for (const renderer of this.barRenderers) {
|
|
60232
|
+
renderer.registerMultiSystemSlurs(this.system.layout.slurRegistry.getAllContinuations(renderer));
|
|
60233
|
+
if (renderer.finalizeRenderer()) {
|
|
59566
60234
|
needsSecondPass = true;
|
|
59567
60235
|
}
|
|
59568
|
-
this.height = Math.max(this.height,
|
|
60236
|
+
this.height = Math.max(this.height, renderer.height);
|
|
59569
60237
|
}
|
|
59570
60238
|
// 2nd pass: move renderers to correct position respecting the new overflows
|
|
59571
60239
|
if (needsSecondPass) {
|
|
59572
60240
|
topOverflow = this.topOverflow;
|
|
59573
60241
|
// shift all the renderers to the new position to match required spacing
|
|
59574
|
-
for (
|
|
59575
|
-
|
|
60242
|
+
for (const renderer of this.barRenderers) {
|
|
60243
|
+
renderer.y = this.topPadding + topOverflow;
|
|
59576
60244
|
}
|
|
59577
60245
|
// finalize again (to align ties)
|
|
59578
|
-
for (
|
|
59579
|
-
|
|
60246
|
+
for (const renderer of this.barRenderers) {
|
|
60247
|
+
renderer.finalizeRenderer();
|
|
59580
60248
|
}
|
|
59581
60249
|
}
|
|
59582
60250
|
if (this.height > 0) {
|
|
@@ -60182,6 +60850,7 @@ class StaffSystem {
|
|
|
60182
60850
|
if (newBarDisplayScale > barDisplayScale) {
|
|
60183
60851
|
barDisplayScale = newBarDisplayScale;
|
|
60184
60852
|
}
|
|
60853
|
+
lastBar.afterReverted();
|
|
60185
60854
|
}
|
|
60186
60855
|
this.width -= width;
|
|
60187
60856
|
this.computedWidth -= width;
|
|
@@ -60701,12 +61370,16 @@ class ScoreLayout {
|
|
|
60701
61370
|
constructor(renderer) {
|
|
60702
61371
|
this.renderer = renderer;
|
|
60703
61372
|
}
|
|
61373
|
+
slurRegistry = new SlurRegistry();
|
|
60704
61374
|
resize() {
|
|
60705
61375
|
this._lazyPartials.clear();
|
|
61376
|
+
this.slurRegistry.clear();
|
|
60706
61377
|
this.doResize();
|
|
60707
61378
|
}
|
|
60708
61379
|
layoutAndRender() {
|
|
60709
61380
|
this._lazyPartials.clear();
|
|
61381
|
+
this.slurRegistry.clear();
|
|
61382
|
+
this._barRendererLookup.clear();
|
|
60710
61383
|
this.profile = Environment.staveProfiles.get(this.renderer.settings.display.staveProfile);
|
|
60711
61384
|
const score = this.renderer.score;
|
|
60712
61385
|
this.firstBarIndex = ModelUtils.computeFirstDisplayedBarIndex(score, this.renderer.settings);
|
|
@@ -60975,17 +61648,6 @@ class ScoreLayout {
|
|
|
60975
61648
|
}
|
|
60976
61649
|
}
|
|
60977
61650
|
}
|
|
60978
|
-
unregisterBarRenderer(key, renderer) {
|
|
60979
|
-
if (this._barRendererLookup.has(key)) {
|
|
60980
|
-
const lookup = this._barRendererLookup.get(key);
|
|
60981
|
-
lookup.delete(renderer.bar.id);
|
|
60982
|
-
if (renderer.additionalMultiRestBars) {
|
|
60983
|
-
for (const b of renderer.additionalMultiRestBars) {
|
|
60984
|
-
lookup.delete(b.id);
|
|
60985
|
-
}
|
|
60986
|
-
}
|
|
60987
|
-
}
|
|
60988
|
-
}
|
|
60989
61651
|
getRendererForBar(key, bar) {
|
|
60990
61652
|
const barRendererId = bar.id;
|
|
60991
61653
|
if (this._barRendererLookup.has(key) && this._barRendererLookup.get(key).has(barRendererId)) {
|
|
@@ -61974,6 +62636,7 @@ class BarRendererBase {
|
|
|
61974
62636
|
_voiceContainers = new Map();
|
|
61975
62637
|
_postBeatGlyphs = new LeftToRightLayoutingGlyphGroup();
|
|
61976
62638
|
_ties = [];
|
|
62639
|
+
_multiSystemSlurs;
|
|
61977
62640
|
topEffects;
|
|
61978
62641
|
bottomEffects;
|
|
61979
62642
|
get nextRenderer() {
|
|
@@ -62126,6 +62789,11 @@ class BarRendererBase {
|
|
|
62126
62789
|
}
|
|
62127
62790
|
}
|
|
62128
62791
|
_appliedLayoutingInfo = 0;
|
|
62792
|
+
afterReverted() {
|
|
62793
|
+
this.staff = undefined;
|
|
62794
|
+
this.registerMultiSystemSlurs(undefined);
|
|
62795
|
+
this.isFinalized = false;
|
|
62796
|
+
}
|
|
62129
62797
|
afterStaffBarReverted() {
|
|
62130
62798
|
this.topEffects.afterStaffBarReverted();
|
|
62131
62799
|
this.bottomEffects.afterStaffBarReverted();
|
|
@@ -62171,13 +62839,26 @@ class BarRendererBase {
|
|
|
62171
62839
|
return true;
|
|
62172
62840
|
}
|
|
62173
62841
|
isFinalized = false;
|
|
62174
|
-
|
|
62175
|
-
|
|
62842
|
+
registerMultiSystemSlurs(startedTies) {
|
|
62843
|
+
if (!startedTies) {
|
|
62844
|
+
this._multiSystemSlurs = undefined;
|
|
62845
|
+
return;
|
|
62846
|
+
}
|
|
62847
|
+
let ties = undefined;
|
|
62848
|
+
for (const g of startedTies) {
|
|
62849
|
+
const continuation = new ContinuationTieGlyph(g);
|
|
62850
|
+
continuation.renderer = this;
|
|
62851
|
+
continuation.tieDirection = g.tieDirection;
|
|
62852
|
+
if (!ties) {
|
|
62853
|
+
ties = [];
|
|
62854
|
+
}
|
|
62855
|
+
ties.push(continuation);
|
|
62856
|
+
}
|
|
62857
|
+
this._multiSystemSlurs = ties;
|
|
62858
|
+
}
|
|
62859
|
+
_finalizeTies(ties, barTop, barBottom) {
|
|
62176
62860
|
let didChangeOverflows = false;
|
|
62177
|
-
|
|
62178
|
-
const barTop = this.y;
|
|
62179
|
-
const barBottom = this.y + this.height;
|
|
62180
|
-
for (const t of this._ties) {
|
|
62861
|
+
for (const t of ties) {
|
|
62181
62862
|
const tie = t;
|
|
62182
62863
|
tie.doLayout();
|
|
62183
62864
|
if (t.checkForOverflow) {
|
|
@@ -62198,6 +62879,21 @@ class BarRendererBase {
|
|
|
62198
62879
|
}
|
|
62199
62880
|
}
|
|
62200
62881
|
}
|
|
62882
|
+
return didChangeOverflows;
|
|
62883
|
+
}
|
|
62884
|
+
finalizeRenderer() {
|
|
62885
|
+
this.isFinalized = true;
|
|
62886
|
+
let didChangeOverflows = false;
|
|
62887
|
+
// allow spacing to be used for tie overflows
|
|
62888
|
+
const barTop = this.y;
|
|
62889
|
+
const barBottom = this.y + this.height;
|
|
62890
|
+
if (this._finalizeTies(this._ties, barTop, barBottom)) {
|
|
62891
|
+
didChangeOverflows = true;
|
|
62892
|
+
}
|
|
62893
|
+
const multiSystemSlurs = this._multiSystemSlurs;
|
|
62894
|
+
if (multiSystemSlurs && this._finalizeTies(multiSystemSlurs, barTop, barBottom)) {
|
|
62895
|
+
didChangeOverflows = true;
|
|
62896
|
+
}
|
|
62201
62897
|
const topHeightChanged = this.topEffects.finalizeEffects();
|
|
62202
62898
|
const bottomHeightChanged = this.bottomEffects.finalizeEffects();
|
|
62203
62899
|
if (topHeightChanged || bottomHeightChanged) {
|
|
@@ -62378,6 +63074,16 @@ class BarRendererBase {
|
|
|
62378
63074
|
}
|
|
62379
63075
|
canvas.color = this.resources.mainGlyphColor;
|
|
62380
63076
|
this._postBeatGlyphs.paint(cx + this.x, cy + this.y, canvas);
|
|
63077
|
+
this._paintMultiSystemSlurs(cx, cy, canvas);
|
|
63078
|
+
}
|
|
63079
|
+
_paintMultiSystemSlurs(cx, cy, canvas) {
|
|
63080
|
+
const multiSystemSlurs = this._multiSystemSlurs;
|
|
63081
|
+
if (!multiSystemSlurs) {
|
|
63082
|
+
return;
|
|
63083
|
+
}
|
|
63084
|
+
for (const slur of multiSystemSlurs) {
|
|
63085
|
+
slur.paint(cx, cy, canvas);
|
|
63086
|
+
}
|
|
62381
63087
|
}
|
|
62382
63088
|
paintBackground(cx, cy, canvas) {
|
|
62383
63089
|
this.layoutingInfo.paint(cx + this.x + this._preBeatGlyphs.x + this._preBeatGlyphs.width, cy + this.y + this.height, canvas);
|
|
@@ -64456,6 +65162,13 @@ class PageViewLayout extends ScoreLayout {
|
|
|
64456
65162
|
}
|
|
64457
65163
|
}
|
|
64458
65164
|
else {
|
|
65165
|
+
// clear out staves during re-layout, this info is outdated during
|
|
65166
|
+
// re-layout of the bars
|
|
65167
|
+
for (const r of this._allMasterBarRenderers) {
|
|
65168
|
+
for (const b of r.renderers) {
|
|
65169
|
+
b.afterReverted();
|
|
65170
|
+
}
|
|
65171
|
+
}
|
|
64459
65172
|
this._systems = [];
|
|
64460
65173
|
let currentIndex = 0;
|
|
64461
65174
|
const maxWidth = this._maxWidth;
|
|
@@ -64917,7 +65630,7 @@ class BarLineGlyph extends LeftToRightLayoutingGlyphGroup {
|
|
|
64917
65630
|
// as during layout things are still moving
|
|
64918
65631
|
let actualLineHeight = this.height;
|
|
64919
65632
|
const thisStaff = renderer.staff;
|
|
64920
|
-
const allStaves =
|
|
65633
|
+
const allStaves = thisStaff.system.allStaves;
|
|
64921
65634
|
let isExtended = false;
|
|
64922
65635
|
if (this._extendToNextStaff && thisStaff.index < allStaves.length - 1) {
|
|
64923
65636
|
const nextStaff = allStaves[thisStaff.index + 1];
|
|
@@ -65099,7 +65812,7 @@ class LineBarRenderer extends BarRendererBase {
|
|
|
65099
65812
|
}
|
|
65100
65813
|
// during system fitting it can happen that we have fraction widths
|
|
65101
65814
|
// but to have lines until the full end-pixel we round up.
|
|
65102
|
-
// this way we avoid holes,
|
|
65815
|
+
// this way we avoid holes,
|
|
65103
65816
|
const lineWidth = this.width;
|
|
65104
65817
|
// we want the lines to be exactly virtually aligned with the respective Y-position
|
|
65105
65818
|
// for note heads to align correctly
|
|
@@ -65865,375 +66578,23 @@ class LineBarRenderer extends BarRendererBase {
|
|
|
65865
66578
|
/**
|
|
65866
66579
|
* @internal
|
|
65867
66580
|
*/
|
|
65868
|
-
class
|
|
65869
|
-
startBeat;
|
|
65870
|
-
endBeat;
|
|
65871
|
-
yOffset = 0;
|
|
65872
|
-
forEnd;
|
|
65873
|
-
startNoteRenderer = null;
|
|
65874
|
-
endNoteRenderer = null;
|
|
65875
|
-
tieDirection = BeamDirection.Up;
|
|
65876
|
-
constructor(startBeat, endBeat, forEnd) {
|
|
65877
|
-
super(0, 0);
|
|
65878
|
-
this.startBeat = startBeat;
|
|
65879
|
-
this.endBeat = endBeat;
|
|
65880
|
-
this.forEnd = forEnd;
|
|
65881
|
-
}
|
|
65882
|
-
_startX = 0;
|
|
65883
|
-
_startY = 0;
|
|
65884
|
-
_endX = 0;
|
|
65885
|
-
_endY = 0;
|
|
65886
|
-
_tieHeight = 0;
|
|
65887
|
-
_shouldDraw = false;
|
|
65888
|
-
_boundingBox;
|
|
65889
|
-
get checkForOverflow() {
|
|
65890
|
-
return this._boundingBox !== undefined;
|
|
65891
|
-
}
|
|
65892
|
-
getBoundingBoxTop() {
|
|
65893
|
-
if (this._boundingBox) {
|
|
65894
|
-
return this._boundingBox.y;
|
|
65895
|
-
}
|
|
65896
|
-
return this._startY;
|
|
65897
|
-
}
|
|
65898
|
-
getBoundingBoxBottom() {
|
|
65899
|
-
if (this._boundingBox) {
|
|
65900
|
-
return this._boundingBox.y + this._boundingBox.h;
|
|
65901
|
-
}
|
|
65902
|
-
return this._startY;
|
|
65903
|
-
}
|
|
65904
|
-
doLayout() {
|
|
65905
|
-
this.width = 0;
|
|
65906
|
-
// TODO fix nullability of start/end beat,
|
|
65907
|
-
if (!this.endBeat) {
|
|
65908
|
-
this._shouldDraw = false;
|
|
65909
|
-
return;
|
|
65910
|
-
}
|
|
65911
|
-
const startNoteRenderer = this.renderer.scoreRenderer.layout.getRendererForBar(this.renderer.staff.staffId, this.startBeat.voice.bar);
|
|
65912
|
-
this.startNoteRenderer = startNoteRenderer;
|
|
65913
|
-
const endNoteRenderer = this.renderer.scoreRenderer.layout.getRendererForBar(this.renderer.staff.staffId, this.endBeat.voice.bar);
|
|
65914
|
-
this.endNoteRenderer = endNoteRenderer;
|
|
65915
|
-
this._startX = 0;
|
|
65916
|
-
this._endX = 0;
|
|
65917
|
-
this._startY = 0;
|
|
65918
|
-
this._endY = 0;
|
|
65919
|
-
this.height = 0;
|
|
65920
|
-
this._shouldDraw = false;
|
|
65921
|
-
// if we are on the tie start, we check if we
|
|
65922
|
-
// either can draw till the end note, or we just can draw till the bar end
|
|
65923
|
-
this.tieDirection = !startNoteRenderer
|
|
65924
|
-
? this.getBeamDirection(this.endBeat, endNoteRenderer)
|
|
65925
|
-
: this.getBeamDirection(this.startBeat, startNoteRenderer);
|
|
65926
|
-
if (!this.forEnd && startNoteRenderer) {
|
|
65927
|
-
// line break or bar break
|
|
65928
|
-
if (startNoteRenderer !== endNoteRenderer) {
|
|
65929
|
-
this._startX = startNoteRenderer.x + this.getStartX();
|
|
65930
|
-
this._startY = startNoteRenderer.y + this.getStartY() + this.yOffset;
|
|
65931
|
-
// line break: to bar end
|
|
65932
|
-
if (!endNoteRenderer || startNoteRenderer.staff !== endNoteRenderer.staff) {
|
|
65933
|
-
this._endX = startNoteRenderer.x + startNoteRenderer.width;
|
|
65934
|
-
this._endY = this._startY;
|
|
65935
|
-
}
|
|
65936
|
-
else {
|
|
65937
|
-
this._endX = endNoteRenderer.x + this.getEndX();
|
|
65938
|
-
this._endY = endNoteRenderer.y + this.getEndY() + this.yOffset;
|
|
65939
|
-
}
|
|
65940
|
-
}
|
|
65941
|
-
else {
|
|
65942
|
-
this._startX = startNoteRenderer.x + this.getStartX();
|
|
65943
|
-
this._endX = endNoteRenderer.x + this.getEndX();
|
|
65944
|
-
this._startY = startNoteRenderer.y + this.getStartY() + this.yOffset;
|
|
65945
|
-
this._endY = endNoteRenderer.y + this.getEndY() + this.yOffset;
|
|
65946
|
-
}
|
|
65947
|
-
this._shouldDraw = true;
|
|
65948
|
-
}
|
|
65949
|
-
else if (!startNoteRenderer || startNoteRenderer.staff !== endNoteRenderer.staff) {
|
|
65950
|
-
this._startX = endNoteRenderer.x;
|
|
65951
|
-
this._endX = endNoteRenderer.x + this.getEndX();
|
|
65952
|
-
this._startY = endNoteRenderer.y + this.getEndY() + this.yOffset;
|
|
65953
|
-
this._endY = this._startY;
|
|
65954
|
-
this._shouldDraw = true;
|
|
65955
|
-
}
|
|
65956
|
-
this._boundingBox = undefined;
|
|
65957
|
-
if (this._shouldDraw) {
|
|
65958
|
-
this.y = Math.min(this._startY, this._endY);
|
|
65959
|
-
if (this.shouldDrawBendSlur()) {
|
|
65960
|
-
this._tieHeight = 0; // TODO: Bend slur height to be considered?
|
|
65961
|
-
}
|
|
65962
|
-
else {
|
|
65963
|
-
this._tieHeight = this.getTieHeight(this._startX, this._startY, this._endX, this._endY);
|
|
65964
|
-
const tieBoundingBox = TieGlyph.calculateActualTieHeight(1, this._startX, this._startY, this._endX, this._endY, this.tieDirection === BeamDirection.Down, this._tieHeight, this.renderer.smuflMetrics.tieMidpointThickness);
|
|
65965
|
-
this._boundingBox = tieBoundingBox;
|
|
65966
|
-
this.height = tieBoundingBox.h;
|
|
65967
|
-
if (this.tieDirection === BeamDirection.Up) {
|
|
65968
|
-
// the tie might go above `this.y` due to its shape
|
|
65969
|
-
// here we calculate how much this is so we can consider the
|
|
65970
|
-
// respective overflow
|
|
65971
|
-
const overlap = this.y - tieBoundingBox.y;
|
|
65972
|
-
if (overlap > 0) {
|
|
65973
|
-
this.y -= overlap;
|
|
65974
|
-
}
|
|
65975
|
-
}
|
|
65976
|
-
}
|
|
65977
|
-
}
|
|
65978
|
-
}
|
|
65979
|
-
paint(cx, cy, canvas) {
|
|
65980
|
-
if (this._shouldDraw) {
|
|
65981
|
-
if (this.shouldDrawBendSlur()) {
|
|
65982
|
-
TieGlyph.drawBendSlur(canvas, cx + this._startX, cy + this._startY, cx + this._endX, cy + this._endY, this.tieDirection === BeamDirection.Down, 1, this.renderer.smuflMetrics.tieHeight);
|
|
65983
|
-
}
|
|
65984
|
-
else {
|
|
65985
|
-
TieGlyph.paintTie(canvas, 1, cx + this._startX, cy + this._startY, cx + this._endX, cy + this._endY, this.tieDirection === BeamDirection.Down, this._tieHeight, this.renderer.smuflMetrics.tieMidpointThickness);
|
|
65986
|
-
}
|
|
65987
|
-
}
|
|
65988
|
-
}
|
|
65989
|
-
shouldDrawBendSlur() {
|
|
65990
|
-
return false;
|
|
65991
|
-
}
|
|
65992
|
-
getTieHeight(_startX, _startY, _endX, _endY) {
|
|
65993
|
-
return this.renderer.smuflMetrics.tieHeight;
|
|
65994
|
-
}
|
|
65995
|
-
getBeamDirection(_beat, _noteRenderer) {
|
|
65996
|
-
return BeamDirection.Down;
|
|
65997
|
-
}
|
|
65998
|
-
getStartY() {
|
|
65999
|
-
return 0;
|
|
66000
|
-
}
|
|
66001
|
-
getEndY() {
|
|
66002
|
-
return 0;
|
|
66003
|
-
}
|
|
66004
|
-
getStartX() {
|
|
66005
|
-
return 0;
|
|
66006
|
-
}
|
|
66007
|
-
getEndX() {
|
|
66008
|
-
return 0;
|
|
66009
|
-
}
|
|
66010
|
-
static calculateActualTieHeight(scale, x1, y1, x2, y2, down, offset, size) {
|
|
66011
|
-
const cp = TieGlyph._computeBezierControlPoints(scale, x1, y1, x2, y2, down, offset, size);
|
|
66012
|
-
// For a musical tie/slur, the extrema occur predictably near the midpoint
|
|
66013
|
-
// Evaluate at midpoint (t=0.5) and check endpoints
|
|
66014
|
-
const p0x = cp[0];
|
|
66015
|
-
const p0y = cp[1];
|
|
66016
|
-
const c1x = cp[2];
|
|
66017
|
-
const c1y = cp[3];
|
|
66018
|
-
const c2x = cp[4];
|
|
66019
|
-
const c2y = cp[5];
|
|
66020
|
-
const p1x = cp[6];
|
|
66021
|
-
const p1y = cp[7];
|
|
66022
|
-
// Evaluate at t=0.5 for midpoint
|
|
66023
|
-
const midX = 0.125 * p0x + 0.375 * c1x + 0.375 * c2x + 0.125 * p1x;
|
|
66024
|
-
const midY = 0.125 * p0y + 0.375 * c1y + 0.375 * c2y + 0.125 * p1y;
|
|
66025
|
-
// Bounds are simply min/max of start, end, and midpoint
|
|
66026
|
-
const xMin = Math.min(p0x, p1x, midX);
|
|
66027
|
-
const xMax = Math.max(p0x, p1x, midX);
|
|
66028
|
-
let yMin = Math.min(p0y, p1y, midY);
|
|
66029
|
-
let yMax = Math.max(p0y, p1y, midY);
|
|
66030
|
-
// Account for thickness of the tie/slur
|
|
66031
|
-
if (down) {
|
|
66032
|
-
yMax += size;
|
|
66033
|
-
}
|
|
66034
|
-
else {
|
|
66035
|
-
yMin -= size;
|
|
66036
|
-
}
|
|
66037
|
-
const b = new Bounds();
|
|
66038
|
-
b.x = xMin;
|
|
66039
|
-
b.y = yMin;
|
|
66040
|
-
b.w = xMax - xMin;
|
|
66041
|
-
b.h = yMax - yMin;
|
|
66042
|
-
return b;
|
|
66043
|
-
}
|
|
66044
|
-
static _computeBezierControlPoints(scale, x1, y1, x2, y2, down, offset, size) {
|
|
66045
|
-
if (x1 === x2 && y1 === y2) {
|
|
66046
|
-
return [];
|
|
66047
|
-
}
|
|
66048
|
-
// ensure endX > startX
|
|
66049
|
-
if (x2 < x1) {
|
|
66050
|
-
let t = x1;
|
|
66051
|
-
x1 = x2;
|
|
66052
|
-
x2 = t;
|
|
66053
|
-
t = y1;
|
|
66054
|
-
y1 = y2;
|
|
66055
|
-
y2 = t;
|
|
66056
|
-
}
|
|
66057
|
-
//
|
|
66058
|
-
// calculate control points
|
|
66059
|
-
//
|
|
66060
|
-
offset *= scale;
|
|
66061
|
-
size *= scale;
|
|
66062
|
-
if (down) {
|
|
66063
|
-
offset *= -1;
|
|
66064
|
-
size *= -1;
|
|
66065
|
-
}
|
|
66066
|
-
if (scale >= 1) {
|
|
66067
|
-
size *= 1.2;
|
|
66068
|
-
}
|
|
66069
|
-
// calculate control points on horizontal axis then rotate:
|
|
66070
|
-
/*
|
|
66071
|
-
cp1x/cpy1 cp2x/cpy2
|
|
66072
|
-
*----------------*
|
|
66073
|
-
/ \
|
|
66074
|
-
/ \
|
|
66075
|
-
x1/y1 * * x2/y2
|
|
66076
|
-
|
|
66077
|
-
cp3 and cp4 are simply with lower height
|
|
66078
|
-
*/
|
|
66079
|
-
const dY = y2 - y1;
|
|
66080
|
-
const dX = x2 - x1;
|
|
66081
|
-
const length = Math.sqrt(dX * dX + dY * dY);
|
|
66082
|
-
let cp1x = x1 + length * 0.25;
|
|
66083
|
-
let cp1y = y1 - offset;
|
|
66084
|
-
let cp2x = x1 + length * 0.75;
|
|
66085
|
-
let cp2y = y1 - offset;
|
|
66086
|
-
let cp3x = x1 + length * 0.75;
|
|
66087
|
-
let cp3y = y1 - offset - size;
|
|
66088
|
-
let cp4x = x1 + length * 0.25;
|
|
66089
|
-
let cp4y = y1 - offset - size;
|
|
66090
|
-
const angle = Math.atan2(dY, dX);
|
|
66091
|
-
[cp1x, cp1y] = TieGlyph._rotate(cp1x, cp1y, x1, y1, angle);
|
|
66092
|
-
[cp2x, cp2y] = TieGlyph._rotate(cp2x, cp2y, x1, y1, angle);
|
|
66093
|
-
[cp3x, cp3y] = TieGlyph._rotate(cp3x, cp3y, x1, y1, angle);
|
|
66094
|
-
[cp4x, cp4y] = TieGlyph._rotate(cp4x, cp4y, x1, y1, angle);
|
|
66095
|
-
return [x1, y1, cp1x, cp1y, cp2x, cp2y, x2, y2, cp3x, cp3y, cp4x, cp4y, x1, y1];
|
|
66096
|
-
}
|
|
66097
|
-
static _rotate(x, y, rotateX, rotateY, angle) {
|
|
66098
|
-
const dx = x - rotateX;
|
|
66099
|
-
const dy = y - rotateY;
|
|
66100
|
-
const rx = dx * Math.cos(angle) - dy * Math.sin(angle);
|
|
66101
|
-
const ry = dx * Math.sin(angle) + dy * Math.cos(angle);
|
|
66102
|
-
return [rotateX + rx, rotateY + ry];
|
|
66103
|
-
}
|
|
66104
|
-
static paintTie(canvas, scale, x1, y1, x2, y2, down /*= false*/, offset /*= 22*/, size /*= 4*/) {
|
|
66105
|
-
const cps = TieGlyph._computeBezierControlPoints(scale, x1, y1, x2, y2, down, offset, size);
|
|
66106
|
-
canvas.beginPath();
|
|
66107
|
-
canvas.moveTo(cps[0], cps[1]);
|
|
66108
|
-
canvas.bezierCurveTo(cps[2], cps[3], cps[4], cps[5], cps[6], cps[7]);
|
|
66109
|
-
canvas.bezierCurveTo(cps[8], cps[9], cps[10], cps[11], cps[12], cps[13]);
|
|
66110
|
-
canvas.closePath();
|
|
66111
|
-
canvas.fill();
|
|
66112
|
-
}
|
|
66113
|
-
static calculateBendSlurTopY(x1, y1, x2, y2, down, scale, bendSlurHeight) {
|
|
66114
|
-
let normalVectorX = y2 - y1;
|
|
66115
|
-
let normalVectorY = x2 - x1;
|
|
66116
|
-
const length = Math.sqrt(normalVectorX * normalVectorX + normalVectorY * normalVectorY);
|
|
66117
|
-
if (down) {
|
|
66118
|
-
normalVectorX *= -1;
|
|
66119
|
-
}
|
|
66120
|
-
else {
|
|
66121
|
-
normalVectorY *= -1;
|
|
66122
|
-
}
|
|
66123
|
-
// make to unit vector
|
|
66124
|
-
normalVectorX /= length;
|
|
66125
|
-
normalVectorY /= length;
|
|
66126
|
-
let offset = bendSlurHeight * scale;
|
|
66127
|
-
if (x2 - x1 < 20) {
|
|
66128
|
-
offset /= 2;
|
|
66129
|
-
}
|
|
66130
|
-
const centerY = (y2 + y1) / 2;
|
|
66131
|
-
const cp1Y = centerY + offset * normalVectorY;
|
|
66132
|
-
return cp1Y;
|
|
66133
|
-
}
|
|
66134
|
-
static drawBendSlur(canvas, x1, y1, x2, y2, down, scale, bendSlurHeight, slurText) {
|
|
66135
|
-
let normalVectorX = y2 - y1;
|
|
66136
|
-
let normalVectorY = x2 - x1;
|
|
66137
|
-
const length = Math.sqrt(normalVectorX * normalVectorX + normalVectorY * normalVectorY);
|
|
66138
|
-
if (down) {
|
|
66139
|
-
normalVectorX *= -1;
|
|
66140
|
-
}
|
|
66141
|
-
else {
|
|
66142
|
-
normalVectorY *= -1;
|
|
66143
|
-
}
|
|
66144
|
-
// make to unit vector
|
|
66145
|
-
normalVectorX /= length;
|
|
66146
|
-
normalVectorY /= length;
|
|
66147
|
-
// center of connection
|
|
66148
|
-
// TODO: should be 1/3
|
|
66149
|
-
const centerX = (x2 + x1) / 2;
|
|
66150
|
-
const centerY = (y2 + y1) / 2;
|
|
66151
|
-
let offset = bendSlurHeight * scale;
|
|
66152
|
-
if (x2 - x1 < 20) {
|
|
66153
|
-
offset /= 2;
|
|
66154
|
-
}
|
|
66155
|
-
const cp1X = centerX + offset * normalVectorX;
|
|
66156
|
-
const cp1Y = centerY + offset * normalVectorY;
|
|
66157
|
-
canvas.beginPath();
|
|
66158
|
-
canvas.moveTo(x1, y1);
|
|
66159
|
-
canvas.lineTo(cp1X, cp1Y);
|
|
66160
|
-
canvas.lineTo(x2, y2);
|
|
66161
|
-
canvas.stroke();
|
|
66162
|
-
if (slurText) {
|
|
66163
|
-
const w = canvas.measureText(slurText).width;
|
|
66164
|
-
const textOffset = down ? 0 : -canvas.font.size;
|
|
66165
|
-
canvas.fillText(slurText, cp1X - w / 2, cp1Y + textOffset);
|
|
66166
|
-
}
|
|
66167
|
-
}
|
|
66168
|
-
}
|
|
66169
|
-
|
|
66170
|
-
/**
|
|
66171
|
-
* @internal
|
|
66172
|
-
*/
|
|
66173
|
-
class NumberedTieGlyph extends TieGlyph {
|
|
66174
|
-
startNote;
|
|
66175
|
-
endNote;
|
|
66176
|
-
constructor(startNote, endNote, forEnd = false) {
|
|
66177
|
-
super(!startNote ? null : startNote.beat, !endNote ? null : endNote.beat, forEnd);
|
|
66178
|
-
this.startNote = startNote;
|
|
66179
|
-
this.endNote = endNote;
|
|
66180
|
-
}
|
|
66181
|
-
get _isLeftHandTap() {
|
|
66182
|
-
return this.startNote === this.endNote;
|
|
66183
|
-
}
|
|
66581
|
+
class NumberedTieGlyph extends NoteTieGlyph {
|
|
66184
66582
|
shouldDrawBendSlur() {
|
|
66185
66583
|
return (this.renderer.settings.notation.extendBendArrowsOnTiedNotes &&
|
|
66186
66584
|
!!this.startNote.bendOrigin &&
|
|
66187
66585
|
this.startNote.isTieOrigin);
|
|
66188
66586
|
}
|
|
66189
|
-
|
|
66190
|
-
super.doLayout();
|
|
66191
|
-
}
|
|
66192
|
-
getBeamDirection(_beat, _noteRenderer) {
|
|
66587
|
+
calculateTieDirection() {
|
|
66193
66588
|
return BeamDirection.Up;
|
|
66194
66589
|
}
|
|
66195
|
-
getStartY() {
|
|
66196
|
-
return this.startNoteRenderer.getNoteY(this.startNote, NoteYPosition.Top);
|
|
66197
|
-
}
|
|
66198
|
-
getEndY() {
|
|
66199
|
-
return this.getStartY();
|
|
66200
|
-
}
|
|
66201
|
-
getStartX() {
|
|
66202
|
-
if (this._isLeftHandTap) {
|
|
66203
|
-
return this.getEndX() - this.startNoteRenderer.smuflMetrics.leftHandTabTieWidth;
|
|
66204
|
-
}
|
|
66205
|
-
return this.startNoteRenderer.getNoteX(this.startNote, NoteXPosition.Center);
|
|
66206
|
-
}
|
|
66207
|
-
getEndX() {
|
|
66208
|
-
if (this._isLeftHandTap) {
|
|
66209
|
-
return this.endNoteRenderer.getNoteX(this.endNote, NoteXPosition.Left);
|
|
66210
|
-
}
|
|
66211
|
-
return this.endNoteRenderer.getNoteX(this.endNote, NoteXPosition.Center);
|
|
66212
|
-
}
|
|
66213
66590
|
}
|
|
66214
66591
|
|
|
66215
66592
|
/**
|
|
66216
66593
|
* @internal
|
|
66217
66594
|
*/
|
|
66218
|
-
class TabTieGlyph extends
|
|
66219
|
-
|
|
66220
|
-
|
|
66221
|
-
constructor(startNote, endNote, forEnd = false) {
|
|
66222
|
-
super(startNote.beat, endNote.beat, forEnd);
|
|
66223
|
-
this.startNote = startNote;
|
|
66224
|
-
this.endNote = endNote;
|
|
66225
|
-
}
|
|
66226
|
-
get _isLeftHandTap() {
|
|
66227
|
-
return this.startNote === this.endNote;
|
|
66228
|
-
}
|
|
66229
|
-
getTieHeight(startX, startY, endX, endY) {
|
|
66230
|
-
if (this._isLeftHandTap) {
|
|
66231
|
-
return this.startNoteRenderer.smuflMetrics.tieHeight;
|
|
66232
|
-
}
|
|
66233
|
-
return super.getTieHeight(startX, startY, endX, endY);
|
|
66234
|
-
}
|
|
66235
|
-
getBeamDirection(_beat, _noteRenderer) {
|
|
66236
|
-
if (this._isLeftHandTap) {
|
|
66595
|
+
class TabTieGlyph extends NoteTieGlyph {
|
|
66596
|
+
calculateTieDirection() {
|
|
66597
|
+
if (this.isLeftHandTap) {
|
|
66237
66598
|
return BeamDirection.Up;
|
|
66238
66599
|
}
|
|
66239
66600
|
return TabTieGlyph.getBeamDirectionForNote(this.startNote);
|
|
@@ -66241,54 +66602,25 @@ class TabTieGlyph extends TieGlyph {
|
|
|
66241
66602
|
static getBeamDirectionForNote(note) {
|
|
66242
66603
|
return note.string > 3 ? BeamDirection.Up : BeamDirection.Down;
|
|
66243
66604
|
}
|
|
66244
|
-
getStartY() {
|
|
66245
|
-
if (this._isLeftHandTap) {
|
|
66246
|
-
return this.startNoteRenderer.getNoteY(this.startNote, NoteYPosition.Center);
|
|
66247
|
-
}
|
|
66248
|
-
if (this.tieDirection === BeamDirection.Up) {
|
|
66249
|
-
return this.startNoteRenderer.getNoteY(this.startNote, NoteYPosition.Top);
|
|
66250
|
-
}
|
|
66251
|
-
return this.startNoteRenderer.getNoteY(this.startNote, NoteYPosition.Bottom);
|
|
66252
|
-
}
|
|
66253
|
-
getEndY() {
|
|
66254
|
-
return this.getStartY();
|
|
66255
|
-
}
|
|
66256
|
-
getStartX() {
|
|
66257
|
-
if (this._isLeftHandTap) {
|
|
66258
|
-
return this.getEndX() - this.renderer.smuflMetrics.leftHandTabTieWidth;
|
|
66259
|
-
}
|
|
66260
|
-
return this.startNoteRenderer.getNoteX(this.startNote, NoteXPosition.Center);
|
|
66261
|
-
}
|
|
66262
|
-
getEndX() {
|
|
66263
|
-
if (this._isLeftHandTap) {
|
|
66264
|
-
return this.endNoteRenderer.getNoteX(this.endNote, NoteXPosition.Left);
|
|
66265
|
-
}
|
|
66266
|
-
return this.endNoteRenderer.getNoteX(this.endNote, NoteXPosition.Center);
|
|
66267
|
-
}
|
|
66268
66605
|
}
|
|
66269
66606
|
|
|
66270
66607
|
/**
|
|
66271
66608
|
* @internal
|
|
66272
66609
|
*/
|
|
66273
|
-
class
|
|
66274
|
-
_direction;
|
|
66610
|
+
class TabSlurGlyph extends TabTieGlyph {
|
|
66275
66611
|
_forSlide;
|
|
66276
|
-
constructor(startNote, endNote, forSlide, forEnd
|
|
66277
|
-
super(startNote, endNote, forEnd);
|
|
66278
|
-
this._direction = BeamDirection.Up;
|
|
66612
|
+
constructor(slurEffectId, startNote, endNote, forSlide, forEnd) {
|
|
66613
|
+
super(slurEffectId, startNote, endNote, forEnd);
|
|
66279
66614
|
this._forSlide = forSlide;
|
|
66280
66615
|
}
|
|
66281
66616
|
getTieHeight(startX, _startY, endX, _endY) {
|
|
66282
|
-
return Math.log(endX - startX + 1) * this.renderer.settings.notation.slurHeight / 2;
|
|
66617
|
+
return (Math.log(endX - startX + 1) * this.renderer.settings.notation.slurHeight) / 2;
|
|
66283
66618
|
}
|
|
66284
66619
|
tryExpand(startNote, endNote, forSlide, forEnd) {
|
|
66285
66620
|
// same type required
|
|
66286
66621
|
if (this._forSlide !== forSlide) {
|
|
66287
66622
|
return false;
|
|
66288
66623
|
}
|
|
66289
|
-
if (this.forEnd !== forEnd) {
|
|
66290
|
-
return false;
|
|
66291
|
-
}
|
|
66292
66624
|
// same start and endbeat
|
|
66293
66625
|
if (this.startNote.beat.id !== startNote.beat.id) {
|
|
66294
66626
|
return false;
|
|
@@ -66296,41 +66628,43 @@ class NumberedSlurGlyph extends TabTieGlyph {
|
|
|
66296
66628
|
if (this.endNote.beat.id !== endNote.beat.id) {
|
|
66297
66629
|
return false;
|
|
66298
66630
|
}
|
|
66631
|
+
const isForEnd = this.renderer === this.lookupEndBeatRenderer();
|
|
66632
|
+
if (isForEnd !== forEnd) {
|
|
66633
|
+
return false;
|
|
66634
|
+
}
|
|
66635
|
+
// same draw direction
|
|
66636
|
+
if (this.tieDirection !== TabTieGlyph.getBeamDirectionForNote(startNote)) {
|
|
66637
|
+
return false;
|
|
66638
|
+
}
|
|
66299
66639
|
// if we can expand, expand in correct direction
|
|
66300
|
-
switch (this.
|
|
66640
|
+
switch (this.tieDirection) {
|
|
66301
66641
|
case BeamDirection.Up:
|
|
66302
66642
|
if (startNote.realValue > this.startNote.realValue) {
|
|
66303
66643
|
this.startNote = startNote;
|
|
66304
|
-
this.startBeat = startNote.beat;
|
|
66305
66644
|
}
|
|
66306
66645
|
if (endNote.realValue > this.endNote.realValue) {
|
|
66307
66646
|
this.endNote = endNote;
|
|
66308
|
-
this.endBeat = endNote.beat;
|
|
66309
66647
|
}
|
|
66310
66648
|
break;
|
|
66311
66649
|
case BeamDirection.Down:
|
|
66312
66650
|
if (startNote.realValue < this.startNote.realValue) {
|
|
66313
66651
|
this.startNote = startNote;
|
|
66314
|
-
this.startBeat = startNote.beat;
|
|
66315
66652
|
}
|
|
66316
66653
|
if (endNote.realValue < this.endNote.realValue) {
|
|
66317
66654
|
this.endNote = endNote;
|
|
66318
|
-
this.endBeat = endNote.beat;
|
|
66319
66655
|
}
|
|
66320
66656
|
break;
|
|
66321
66657
|
}
|
|
66322
66658
|
return true;
|
|
66323
66659
|
}
|
|
66324
|
-
|
|
66325
|
-
|
|
66326
|
-
|
|
66327
|
-
|
|
66328
|
-
|
|
66329
|
-
|
|
66330
|
-
|
|
66331
|
-
|
|
66332
|
-
super.paint(cx, cy, canvas);
|
|
66333
|
-
}
|
|
66660
|
+
}
|
|
66661
|
+
|
|
66662
|
+
/**
|
|
66663
|
+
* @internal
|
|
66664
|
+
*/
|
|
66665
|
+
class NumberedSlurGlyph extends TabSlurGlyph {
|
|
66666
|
+
calculateTieDirection() {
|
|
66667
|
+
return BeamDirection.Up;
|
|
66334
66668
|
}
|
|
66335
66669
|
}
|
|
66336
66670
|
|
|
@@ -66338,23 +66672,31 @@ class NumberedSlurGlyph extends TabTieGlyph {
|
|
|
66338
66672
|
* @internal
|
|
66339
66673
|
*/
|
|
66340
66674
|
class NumberedBeatContainerGlyph extends BeatContainerGlyph {
|
|
66675
|
+
_slurs = new Map();
|
|
66341
66676
|
_effectSlurs = [];
|
|
66677
|
+
doLayout() {
|
|
66678
|
+
this._slurs.clear();
|
|
66679
|
+
this._effectSlurs = [];
|
|
66680
|
+
super.doLayout();
|
|
66681
|
+
}
|
|
66342
66682
|
createTies(n) {
|
|
66343
66683
|
// create a tie if any effect requires it
|
|
66344
66684
|
if (!n.isVisible) {
|
|
66345
66685
|
return;
|
|
66346
66686
|
}
|
|
66347
|
-
if (n.isTieOrigin && n.tieDestination.isVisible) {
|
|
66348
|
-
const tie = new NumberedTieGlyph(n, n.tieDestination, false);
|
|
66687
|
+
if (n.isTieOrigin && n.tieDestination.isVisible && !this._slurs.has('numbered.tie')) {
|
|
66688
|
+
const tie = new NumberedTieGlyph(`numbered.tie.${n.beat.id}`, n, n.tieDestination, false);
|
|
66349
66689
|
this.addTie(tie);
|
|
66690
|
+
this._slurs.set(tie.slurEffectId, tie);
|
|
66350
66691
|
}
|
|
66351
66692
|
if (n.isTieDestination) {
|
|
66352
|
-
const tie = new NumberedTieGlyph(n.tieOrigin, n, true);
|
|
66693
|
+
const tie = new NumberedTieGlyph(`numbered.tie.${n.tieOrigin.beat.id}`, n.tieOrigin, n, true);
|
|
66353
66694
|
this.addTie(tie);
|
|
66354
66695
|
}
|
|
66355
|
-
if (n.isLeftHandTapped && !n.isHammerPullDestination) {
|
|
66356
|
-
const tapSlur = new NumberedTieGlyph(n, n, false);
|
|
66696
|
+
if (n.isLeftHandTapped && !n.isHammerPullDestination && !this._slurs.has(`numbered.tie.leftHandTap.${n.beat.id}`)) {
|
|
66697
|
+
const tapSlur = new NumberedTieGlyph(`numbered.tie.leftHandTap.${n.beat.id}`, n, n, false);
|
|
66357
66698
|
this.addTie(tapSlur);
|
|
66699
|
+
this._slurs.set(tapSlur.slurEffectId, tapSlur);
|
|
66358
66700
|
}
|
|
66359
66701
|
// start effect slur on first beat
|
|
66360
66702
|
if (n.isEffectSlurOrigin && n.effectSlurDestination) {
|
|
@@ -66366,9 +66708,11 @@ class NumberedBeatContainerGlyph extends BeatContainerGlyph {
|
|
|
66366
66708
|
}
|
|
66367
66709
|
}
|
|
66368
66710
|
if (!expanded) {
|
|
66369
|
-
const effectSlur = new NumberedSlurGlyph(n, n.effectSlurDestination, false, false);
|
|
66711
|
+
const effectSlur = new NumberedSlurGlyph(`numbered.slur.effect`, n, n.effectSlurDestination, false, false);
|
|
66370
66712
|
this._effectSlurs.push(effectSlur);
|
|
66371
66713
|
this.addTie(effectSlur);
|
|
66714
|
+
this._slurs.set(effectSlur.slurEffectId, effectSlur);
|
|
66715
|
+
this._slurs.set('numbered.slur.effect', effectSlur);
|
|
66372
66716
|
}
|
|
66373
66717
|
}
|
|
66374
66718
|
// end effect slur on last beat
|
|
@@ -66381,9 +66725,11 @@ class NumberedBeatContainerGlyph extends BeatContainerGlyph {
|
|
|
66381
66725
|
}
|
|
66382
66726
|
}
|
|
66383
66727
|
if (!expanded) {
|
|
66384
|
-
const effectSlur = new NumberedSlurGlyph(n.effectSlurOrigin, n, false, true);
|
|
66728
|
+
const effectSlur = new NumberedSlurGlyph(`numbered.slur.effect`, n.effectSlurOrigin, n, false, true);
|
|
66385
66729
|
this._effectSlurs.push(effectSlur);
|
|
66386
66730
|
this.addTie(effectSlur);
|
|
66731
|
+
this._slurs.set(effectSlur.slurEffectId, effectSlur);
|
|
66732
|
+
this._slurs.set('numbered.slur.effect', effectSlur);
|
|
66387
66733
|
}
|
|
66388
66734
|
}
|
|
66389
66735
|
}
|
|
@@ -66776,10 +67122,11 @@ class NumberedBeatGlyph extends BeatOnNoteGlyphBase {
|
|
|
66776
67122
|
if (sr.shortestDuration < this.container.beat.duration) {
|
|
66777
67123
|
sr.shortestDuration = this.container.beat.duration;
|
|
66778
67124
|
}
|
|
66779
|
-
const glyphY = sr.getLineY(sr.getNoteLine());
|
|
66780
67125
|
if (!this.container.beat.isEmpty) {
|
|
67126
|
+
const glyphY = sr.getLineY(0);
|
|
66781
67127
|
let numberWithinOctave = '0';
|
|
66782
67128
|
if (this.container.beat.notes.length > 0) {
|
|
67129
|
+
const note = this.container.beat.notes[0];
|
|
66783
67130
|
const kst = this.renderer.bar.keySignatureType;
|
|
66784
67131
|
const ks = this.renderer.bar.keySignature;
|
|
66785
67132
|
const ksi = ks + 7;
|
|
@@ -66787,7 +67134,6 @@ class NumberedBeatGlyph extends BeatOnNoteGlyphBase {
|
|
|
66787
67134
|
? NumberedBeatGlyph.minorKeySignatureOneValues
|
|
66788
67135
|
: NumberedBeatGlyph.majorKeySignatureOneValues;
|
|
66789
67136
|
const oneNoteValue = oneNoteValues[ksi];
|
|
66790
|
-
const note = this.container.beat.notes[0];
|
|
66791
67137
|
if (note.isDead) {
|
|
66792
67138
|
numberWithinOctave = 'X';
|
|
66793
67139
|
}
|
|
@@ -66834,7 +67180,7 @@ class NumberedBeatGlyph extends BeatOnNoteGlyphBase {
|
|
|
66834
67180
|
// Note dots
|
|
66835
67181
|
if (this.container.beat.dots > 0 && this.container.beat.duration >= Duration.Quarter) {
|
|
66836
67182
|
for (let i = 0; i < this.container.beat.dots; i++) {
|
|
66837
|
-
const dot = new AugmentationDotGlyph(0,
|
|
67183
|
+
const dot = new AugmentationDotGlyph(0, glyphY);
|
|
66838
67184
|
dot.renderer = this.renderer;
|
|
66839
67185
|
this.addEffect(dot);
|
|
66840
67186
|
}
|
|
@@ -66862,7 +67208,7 @@ class NumberedBeatGlyph extends BeatOnNoteGlyphBase {
|
|
|
66862
67208
|
numberOfQuarterNotes += numberOfAddedQuarters;
|
|
66863
67209
|
}
|
|
66864
67210
|
for (let i = 0; i < numberOfQuarterNotes - 1; i++) {
|
|
66865
|
-
const dash = new NumberedDashGlyph(0,
|
|
67211
|
+
const dash = new NumberedDashGlyph(0, glyphY, this.container.beat);
|
|
66866
67212
|
dash.renderer = this.renderer;
|
|
66867
67213
|
this.addNormal(dash);
|
|
66868
67214
|
}
|
|
@@ -67332,7 +67678,7 @@ class NumberedBarRenderer extends LineBarRenderer {
|
|
|
67332
67678
|
}
|
|
67333
67679
|
}
|
|
67334
67680
|
}
|
|
67335
|
-
getNoteLine() {
|
|
67681
|
+
getNoteLine(_note) {
|
|
67336
67682
|
return 0;
|
|
67337
67683
|
}
|
|
67338
67684
|
get tupletOffset() {
|
|
@@ -69547,87 +69893,128 @@ class ScoreBendGlyph extends ScoreHelperNotesBaseGlyph {
|
|
|
69547
69893
|
* @internal
|
|
69548
69894
|
*/
|
|
69549
69895
|
class ScoreLegatoGlyph extends TieGlyph {
|
|
69550
|
-
|
|
69551
|
-
|
|
69896
|
+
startBeat;
|
|
69897
|
+
endBeat;
|
|
69898
|
+
startBeatRenderer = null;
|
|
69899
|
+
endBeatRenderer = null;
|
|
69900
|
+
constructor(slurEffectId, startBeat, endBeat, forEnd) {
|
|
69901
|
+
super(slurEffectId, forEnd);
|
|
69902
|
+
this.startBeat = startBeat;
|
|
69903
|
+
this.endBeat = endBeat;
|
|
69552
69904
|
}
|
|
69553
69905
|
doLayout() {
|
|
69554
69906
|
super.doLayout();
|
|
69555
69907
|
}
|
|
69556
|
-
|
|
69557
|
-
if (
|
|
69908
|
+
lookupStartBeatRenderer() {
|
|
69909
|
+
if (!this.startBeatRenderer) {
|
|
69910
|
+
this.startBeatRenderer = this.renderer.scoreRenderer.layout.getRendererForBar(this.renderer.staff.staffId, this.startBeat.voice.bar);
|
|
69911
|
+
}
|
|
69912
|
+
return this.startBeatRenderer;
|
|
69913
|
+
}
|
|
69914
|
+
lookupEndBeatRenderer() {
|
|
69915
|
+
if (!this.endBeatRenderer) {
|
|
69916
|
+
this.endBeatRenderer = this.renderer.scoreRenderer.layout.getRendererForBar(this.renderer.staff.staffId, this.endBeat.voice.bar);
|
|
69917
|
+
}
|
|
69918
|
+
return this.endBeatRenderer;
|
|
69919
|
+
}
|
|
69920
|
+
shouldDrawBendSlur() {
|
|
69921
|
+
return false;
|
|
69922
|
+
}
|
|
69923
|
+
calculateTieDirection() {
|
|
69924
|
+
if (this.startBeat.isRest) {
|
|
69558
69925
|
return BeamDirection.Up;
|
|
69559
69926
|
}
|
|
69560
69927
|
// invert direction (if stems go up, ties go down to not cross them)
|
|
69561
|
-
switch (
|
|
69928
|
+
switch (this.lookupStartBeatRenderer().getBeatDirection(this.startBeat)) {
|
|
69562
69929
|
case BeamDirection.Up:
|
|
69563
69930
|
return BeamDirection.Down;
|
|
69564
69931
|
default:
|
|
69565
69932
|
return BeamDirection.Up;
|
|
69566
69933
|
}
|
|
69567
69934
|
}
|
|
69568
|
-
|
|
69935
|
+
calculateStartX() {
|
|
69936
|
+
const startBeatRenderer = this.lookupStartBeatRenderer();
|
|
69937
|
+
return startBeatRenderer.x + startBeatRenderer.getBeatX(this.startBeat, BeatXPosition.MiddleNotes);
|
|
69938
|
+
}
|
|
69939
|
+
calculateStartY() {
|
|
69940
|
+
const startBeatRenderer = this.lookupStartBeatRenderer();
|
|
69569
69941
|
if (this.startBeat.isRest) {
|
|
69570
|
-
|
|
69571
|
-
|
|
69942
|
+
switch (this.tieDirection) {
|
|
69943
|
+
case BeamDirection.Up:
|
|
69944
|
+
return (startBeatRenderer.y +
|
|
69945
|
+
startBeatRenderer.getBeatContainer(this.startBeat).onNotes.getBoundingBoxTop());
|
|
69946
|
+
default:
|
|
69947
|
+
return (startBeatRenderer.y +
|
|
69948
|
+
startBeatRenderer.getBeatContainer(this.startBeat).onNotes.getBoundingBoxBottom());
|
|
69949
|
+
}
|
|
69572
69950
|
}
|
|
69573
69951
|
switch (this.tieDirection) {
|
|
69574
69952
|
case BeamDirection.Up:
|
|
69575
69953
|
// below lowest note
|
|
69576
|
-
return
|
|
69954
|
+
return startBeatRenderer.y + startBeatRenderer.getNoteY(this.startBeat.maxNote, NoteYPosition.Top);
|
|
69577
69955
|
default:
|
|
69578
|
-
return
|
|
69956
|
+
return startBeatRenderer.y + startBeatRenderer.getNoteY(this.startBeat.minNote, NoteYPosition.Bottom);
|
|
69579
69957
|
}
|
|
69580
69958
|
}
|
|
69581
|
-
|
|
69582
|
-
const
|
|
69959
|
+
calculateEndX() {
|
|
69960
|
+
const endBeatRenderer = this.lookupEndBeatRenderer();
|
|
69961
|
+
if (!endBeatRenderer) {
|
|
69962
|
+
return this.calculateStartX() + this.renderer.smuflMetrics.leftHandTabTieWidth;
|
|
69963
|
+
}
|
|
69964
|
+
const endBeamDirection = endBeatRenderer.getBeatDirection(this.endBeat);
|
|
69965
|
+
return (endBeatRenderer.x +
|
|
69966
|
+
endBeatRenderer.getBeatX(this.endBeat, this.endBeat.duration > Duration.Whole && endBeamDirection === this.tieDirection
|
|
69967
|
+
? BeatXPosition.Stem
|
|
69968
|
+
: BeatXPosition.MiddleNotes));
|
|
69969
|
+
}
|
|
69970
|
+
caclculateEndY() {
|
|
69971
|
+
const endBeatRenderer = this.lookupEndBeatRenderer();
|
|
69972
|
+
if (!endBeatRenderer) {
|
|
69973
|
+
return this.calculateStartY();
|
|
69974
|
+
}
|
|
69583
69975
|
if (this.endBeat.isRest) {
|
|
69584
69976
|
switch (this.tieDirection) {
|
|
69585
69977
|
case BeamDirection.Up:
|
|
69586
|
-
return
|
|
69978
|
+
return (endBeatRenderer.y + endBeatRenderer.getBeatContainer(this.endBeat).onNotes.getBoundingBoxTop());
|
|
69587
69979
|
default:
|
|
69588
|
-
return
|
|
69980
|
+
return (endBeatRenderer.y +
|
|
69981
|
+
endBeatRenderer.getBeatContainer(this.endBeat).onNotes.getBoundingBoxBottom());
|
|
69589
69982
|
}
|
|
69590
69983
|
}
|
|
69591
|
-
const startBeamDirection = this.
|
|
69592
|
-
const endBeamDirection =
|
|
69984
|
+
const startBeamDirection = this.lookupStartBeatRenderer().getBeatDirection(this.startBeat);
|
|
69985
|
+
const endBeamDirection = endBeatRenderer.getBeatDirection(this.endBeat);
|
|
69593
69986
|
if (startBeamDirection !== endBeamDirection && this.startBeat.graceType === GraceType.None) {
|
|
69594
69987
|
if (endBeamDirection === this.tieDirection) {
|
|
69595
69988
|
switch (this.tieDirection) {
|
|
69596
69989
|
case BeamDirection.Up:
|
|
69597
69990
|
// stem upper end
|
|
69598
|
-
return
|
|
69991
|
+
return (endBeatRenderer.y +
|
|
69992
|
+
endBeatRenderer.getNoteY(this.endBeat.maxNote, NoteYPosition.TopWithStem));
|
|
69599
69993
|
default:
|
|
69600
69994
|
// stem lower end
|
|
69601
|
-
return
|
|
69995
|
+
return (endBeatRenderer.y +
|
|
69996
|
+
endBeatRenderer.getNoteY(this.endBeat.minNote, NoteYPosition.BottomWithStem));
|
|
69602
69997
|
}
|
|
69603
69998
|
}
|
|
69604
69999
|
switch (this.tieDirection) {
|
|
69605
70000
|
case BeamDirection.Up:
|
|
69606
70001
|
// stem upper end
|
|
69607
|
-
return
|
|
70002
|
+
return (endBeatRenderer.y +
|
|
70003
|
+
endBeatRenderer.getNoteY(this.endBeat.maxNote, NoteYPosition.BottomWithStem));
|
|
69608
70004
|
default:
|
|
69609
70005
|
// stem lower end
|
|
69610
|
-
return
|
|
70006
|
+
return (endBeatRenderer.y + endBeatRenderer.getNoteY(this.endBeat.minNote, NoteYPosition.TopWithStem));
|
|
69611
70007
|
}
|
|
69612
70008
|
}
|
|
69613
70009
|
switch (this.tieDirection) {
|
|
69614
70010
|
case BeamDirection.Up:
|
|
69615
70011
|
// below lowest note
|
|
69616
|
-
return
|
|
70012
|
+
return endBeatRenderer.y + endBeatRenderer.getNoteY(this.endBeat.maxNote, NoteYPosition.Top);
|
|
69617
70013
|
default:
|
|
69618
70014
|
// above highest note
|
|
69619
|
-
return
|
|
70015
|
+
return endBeatRenderer.y + endBeatRenderer.getNoteY(this.endBeat.minNote, NoteYPosition.Bottom);
|
|
69620
70016
|
}
|
|
69621
70017
|
}
|
|
69622
|
-
getStartX() {
|
|
69623
|
-
return this.startNoteRenderer.getBeatX(this.startBeat, BeatXPosition.MiddleNotes);
|
|
69624
|
-
}
|
|
69625
|
-
getEndX() {
|
|
69626
|
-
const endBeamDirection = this.endNoteRenderer.getBeatDirection(this.endBeat);
|
|
69627
|
-
return this.endNoteRenderer.getBeatX(this.endBeat, this.endBeat.duration > Duration.Whole && endBeamDirection === this.tieDirection
|
|
69628
|
-
? BeatXPosition.Stem
|
|
69629
|
-
: BeatXPosition.MiddleNotes);
|
|
69630
|
-
}
|
|
69631
70018
|
}
|
|
69632
70019
|
|
|
69633
70020
|
/**
|
|
@@ -69827,142 +70214,106 @@ class ScoreSlideLineGlyph extends Glyph {
|
|
|
69827
70214
|
/**
|
|
69828
70215
|
* @internal
|
|
69829
70216
|
*/
|
|
69830
|
-
class
|
|
69831
|
-
|
|
69832
|
-
|
|
69833
|
-
|
|
69834
|
-
|
|
69835
|
-
|
|
69836
|
-
|
|
70217
|
+
class ScoreTieGlyph extends NoteTieGlyph {
|
|
70218
|
+
shouldDrawBendSlur() {
|
|
70219
|
+
return (this.renderer.settings.notation.extendBendArrowsOnTiedNotes &&
|
|
70220
|
+
!!this.startNote.bendOrigin &&
|
|
70221
|
+
this.startNote.isTieOrigin);
|
|
70222
|
+
}
|
|
70223
|
+
calculateStartX() {
|
|
70224
|
+
if (this.isLeftHandTap) {
|
|
70225
|
+
return this.calculateEndX() - this.renderer.smuflMetrics.leftHandTabTieWidth;
|
|
70226
|
+
}
|
|
70227
|
+
return this.renderer.x + this.renderer.getBeatX(this.startNote.beat, BeatXPosition.PostNotes);
|
|
69837
70228
|
}
|
|
70229
|
+
calculateEndX() {
|
|
70230
|
+
const endNoteRenderer = this.lookupEndBeatRenderer();
|
|
70231
|
+
if (!endNoteRenderer) {
|
|
70232
|
+
return this.calculateStartX() + this.renderer.smuflMetrics.leftHandTabTieWidth;
|
|
70233
|
+
}
|
|
70234
|
+
if (this.isLeftHandTap) {
|
|
70235
|
+
return endNoteRenderer.x + endNoteRenderer.getNoteX(this.endNote, NoteXPosition.Left);
|
|
70236
|
+
}
|
|
70237
|
+
return endNoteRenderer.x + endNoteRenderer.getBeatX(this.endNote.beat, BeatXPosition.PreNotes);
|
|
70238
|
+
}
|
|
70239
|
+
}
|
|
70240
|
+
|
|
70241
|
+
/**
|
|
70242
|
+
* @internal
|
|
70243
|
+
*/
|
|
70244
|
+
class ScoreSlurGlyph extends ScoreTieGlyph {
|
|
69838
70245
|
getTieHeight(startX, _startY, endX, _endY) {
|
|
69839
|
-
return Math.log2(endX - startX + 1) * this.renderer.settings.notation.slurHeight / 2;
|
|
70246
|
+
return (Math.log2(endX - startX + 1) * this.renderer.settings.notation.slurHeight) / 2;
|
|
69840
70247
|
}
|
|
69841
|
-
|
|
70248
|
+
calculateStartX() {
|
|
70249
|
+
return (this.renderer.x +
|
|
70250
|
+
(this._isStartCentered()
|
|
70251
|
+
? this.renderer.getBeatX(this.startNote.beat, BeatXPosition.MiddleNotes)
|
|
70252
|
+
: this.renderer.getNoteX(this.startNote, NoteXPosition.Right)));
|
|
70253
|
+
}
|
|
70254
|
+
calculateStartY() {
|
|
69842
70255
|
if (this._isStartCentered()) {
|
|
69843
70256
|
switch (this.tieDirection) {
|
|
69844
70257
|
case BeamDirection.Up:
|
|
69845
|
-
|
|
69846
|
-
return this.startNoteRenderer.getNoteY(this._startNote, NoteYPosition.Top);
|
|
70258
|
+
return this.renderer.y + this.renderer.getNoteY(this.startNote, NoteYPosition.Top);
|
|
69847
70259
|
default:
|
|
69848
|
-
return this.
|
|
70260
|
+
return this.renderer.y + this.renderer.getNoteY(this.startNote, NoteYPosition.Bottom);
|
|
69849
70261
|
}
|
|
69850
70262
|
}
|
|
69851
|
-
return this.
|
|
70263
|
+
return this.renderer.y + this.renderer.getNoteY(this.startNote, NoteYPosition.Center);
|
|
69852
70264
|
}
|
|
69853
|
-
|
|
70265
|
+
calculateEndX() {
|
|
70266
|
+
const endNoteRenderer = this.lookupEndBeatRenderer();
|
|
70267
|
+
if (!endNoteRenderer) {
|
|
70268
|
+
return this.calculateStartX() + this.renderer.smuflMetrics.leftHandTabTieWidth;
|
|
70269
|
+
}
|
|
70270
|
+
if (this._isEndCentered()) {
|
|
70271
|
+
if (this._isEndOnStem()) {
|
|
70272
|
+
return endNoteRenderer.x + endNoteRenderer.getBeatX(this.endNote.beat, BeatXPosition.Stem);
|
|
70273
|
+
}
|
|
70274
|
+
return endNoteRenderer.x + endNoteRenderer.getNoteX(this.endNote, NoteXPosition.Center);
|
|
70275
|
+
}
|
|
70276
|
+
return endNoteRenderer.x + endNoteRenderer.getBeatX(this.endNote.beat, BeatXPosition.PreNotes);
|
|
70277
|
+
}
|
|
70278
|
+
caclculateEndY() {
|
|
70279
|
+
const endNoteRenderer = this.lookupEndBeatRenderer();
|
|
70280
|
+
if (!endNoteRenderer) {
|
|
70281
|
+
return this.calculateStartY();
|
|
70282
|
+
}
|
|
69854
70283
|
if (this._isEndCentered()) {
|
|
69855
70284
|
if (this._isEndOnStem()) {
|
|
69856
70285
|
switch (this.tieDirection) {
|
|
69857
70286
|
case BeamDirection.Up:
|
|
69858
|
-
return
|
|
70287
|
+
return endNoteRenderer.y + endNoteRenderer.getNoteY(this.endNote, NoteYPosition.TopWithStem);
|
|
69859
70288
|
default:
|
|
69860
|
-
return
|
|
70289
|
+
return endNoteRenderer.y + endNoteRenderer.getNoteY(this.endNote, NoteYPosition.BottomWithStem);
|
|
69861
70290
|
}
|
|
69862
70291
|
}
|
|
69863
70292
|
switch (this.tieDirection) {
|
|
69864
70293
|
case BeamDirection.Up:
|
|
69865
|
-
return
|
|
70294
|
+
return endNoteRenderer.y + endNoteRenderer.getNoteY(this.endNote, NoteYPosition.Top);
|
|
69866
70295
|
default:
|
|
69867
|
-
return
|
|
70296
|
+
return endNoteRenderer.y + endNoteRenderer.getNoteY(this.endNote, NoteYPosition.Bottom);
|
|
69868
70297
|
}
|
|
69869
70298
|
}
|
|
69870
|
-
return
|
|
70299
|
+
return endNoteRenderer.y + endNoteRenderer.getNoteY(this.endNote, NoteYPosition.Center);
|
|
69871
70300
|
}
|
|
69872
70301
|
_isStartCentered() {
|
|
69873
|
-
return ((this.
|
|
69874
|
-
(this.
|
|
70302
|
+
return ((this.startNote === this.startNote.beat.maxNote && this.tieDirection === BeamDirection.Up) ||
|
|
70303
|
+
(this.startNote === this.startNote.beat.minNote && this.tieDirection === BeamDirection.Down));
|
|
69875
70304
|
}
|
|
69876
70305
|
_isEndCentered() {
|
|
69877
|
-
return (this.
|
|
69878
|
-
((this.
|
|
69879
|
-
(this.
|
|
70306
|
+
return (this.startNote.beat.graceType === GraceType.None &&
|
|
70307
|
+
((this.endNote === this.endNote.beat.maxNote && this.tieDirection === BeamDirection.Up) ||
|
|
70308
|
+
(this.endNote === this.endNote.beat.minNote && this.tieDirection === BeamDirection.Down)));
|
|
69880
70309
|
}
|
|
69881
70310
|
_isEndOnStem() {
|
|
69882
|
-
const
|
|
69883
|
-
const
|
|
69884
|
-
const endBeamDirection =
|
|
69885
|
-
|
|
69886
|
-
|
|
69887
|
-
|
|
69888
|
-
return this._isStartCentered()
|
|
69889
|
-
? this.startNoteRenderer.getBeatX(this._startNote.beat, BeatXPosition.MiddleNotes)
|
|
69890
|
-
: this.startNoteRenderer.getNoteX(this._startNote, NoteXPosition.Right);
|
|
69891
|
-
}
|
|
69892
|
-
getEndX() {
|
|
69893
|
-
if (this._isEndCentered()) {
|
|
69894
|
-
if (this._isEndOnStem()) {
|
|
69895
|
-
return this.endNoteRenderer.getBeatX(this._endNote.beat, BeatXPosition.Stem);
|
|
69896
|
-
}
|
|
69897
|
-
return this.endNoteRenderer.getNoteX(this._endNote, NoteXPosition.Center);
|
|
69898
|
-
}
|
|
69899
|
-
return this.endNoteRenderer.getBeatX(this._endNote.beat, BeatXPosition.PreNotes);
|
|
69900
|
-
}
|
|
69901
|
-
}
|
|
69902
|
-
|
|
69903
|
-
/**
|
|
69904
|
-
* @internal
|
|
69905
|
-
*/
|
|
69906
|
-
class ScoreTieGlyph extends TieGlyph {
|
|
69907
|
-
startNote;
|
|
69908
|
-
endNote;
|
|
69909
|
-
constructor(startNote, endNote, forEnd = false) {
|
|
69910
|
-
super(!startNote ? null : startNote.beat, !endNote ? null : endNote.beat, forEnd);
|
|
69911
|
-
this.startNote = startNote;
|
|
69912
|
-
this.endNote = endNote;
|
|
69913
|
-
}
|
|
69914
|
-
shouldDrawBendSlur() {
|
|
69915
|
-
return (this.renderer.settings.notation.extendBendArrowsOnTiedNotes &&
|
|
69916
|
-
!!this.startNote.bendOrigin &&
|
|
69917
|
-
this.startNote.isTieOrigin);
|
|
69918
|
-
}
|
|
69919
|
-
doLayout() {
|
|
69920
|
-
super.doLayout();
|
|
69921
|
-
}
|
|
69922
|
-
getBeamDirection(beat, noteRenderer) {
|
|
69923
|
-
// invert direction (if stems go up, ties go down to not cross them)
|
|
69924
|
-
switch (noteRenderer.getBeatDirection(beat)) {
|
|
69925
|
-
case BeamDirection.Up:
|
|
69926
|
-
return BeamDirection.Down;
|
|
69927
|
-
default:
|
|
69928
|
-
return BeamDirection.Up;
|
|
69929
|
-
}
|
|
69930
|
-
}
|
|
69931
|
-
getStartY() {
|
|
69932
|
-
if (this.startBeat.isRest) {
|
|
69933
|
-
// below all lines
|
|
69934
|
-
return this.startNoteRenderer.getScoreY(9);
|
|
69935
|
-
}
|
|
69936
|
-
switch (this.tieDirection) {
|
|
69937
|
-
case BeamDirection.Up:
|
|
69938
|
-
// below lowest note
|
|
69939
|
-
return this.startNoteRenderer.getNoteY(this.startNote, NoteYPosition.Top);
|
|
69940
|
-
default:
|
|
69941
|
-
return this.startNoteRenderer.getNoteY(this.startNote, NoteYPosition.Bottom);
|
|
69942
|
-
}
|
|
69943
|
-
}
|
|
69944
|
-
getEndY() {
|
|
69945
|
-
const endNoteScoreRenderer = this.endNoteRenderer;
|
|
69946
|
-
if (this.endBeat.isRest) {
|
|
69947
|
-
switch (this.tieDirection) {
|
|
69948
|
-
case BeamDirection.Up:
|
|
69949
|
-
return endNoteScoreRenderer.getScoreY(9);
|
|
69950
|
-
default:
|
|
69951
|
-
return endNoteScoreRenderer.getScoreY(0);
|
|
69952
|
-
}
|
|
69953
|
-
}
|
|
69954
|
-
switch (this.tieDirection) {
|
|
69955
|
-
case BeamDirection.Up:
|
|
69956
|
-
return endNoteScoreRenderer.getNoteY(this.endNote, NoteYPosition.Top);
|
|
69957
|
-
default:
|
|
69958
|
-
return endNoteScoreRenderer.getNoteY(this.endNote, NoteYPosition.Bottom);
|
|
69959
|
-
}
|
|
69960
|
-
}
|
|
69961
|
-
getStartX() {
|
|
69962
|
-
return this.startNoteRenderer.getBeatX(this.startNote.beat, BeatXPosition.PostNotes);
|
|
69963
|
-
}
|
|
69964
|
-
getEndX() {
|
|
69965
|
-
return this.endNoteRenderer.getBeatX(this.endNote.beat, BeatXPosition.PreNotes);
|
|
70311
|
+
const startBeamDirection = this.lookupStartBeatRenderer().getBeatDirection(this.startNote.beat);
|
|
70312
|
+
const endBeatRenderer = this.lookupEndBeatRenderer();
|
|
70313
|
+
const endBeamDirection = endBeatRenderer
|
|
70314
|
+
? endBeatRenderer.getBeatDirection(this.endNote.beat)
|
|
70315
|
+
: startBeamDirection;
|
|
70316
|
+
return startBeamDirection !== endBeamDirection && this.startNote.beat.graceType === GraceType.None;
|
|
69966
70317
|
}
|
|
69967
70318
|
}
|
|
69968
70319
|
|
|
@@ -70012,12 +70363,11 @@ class ScoreBeatContainerGlyph extends BeatContainerGlyph {
|
|
|
70012
70363
|
n.beat.graceType !== GraceType.BendGrace &&
|
|
70013
70364
|
n.tieDestination &&
|
|
70014
70365
|
n.tieDestination.isVisible) {
|
|
70015
|
-
|
|
70016
|
-
const tie = new ScoreTieGlyph(n, n.tieDestination, false);
|
|
70366
|
+
const tie = new ScoreTieGlyph(`score.tie.${n.id}`, n, n.tieDestination, false);
|
|
70017
70367
|
this.addTie(tie);
|
|
70018
70368
|
}
|
|
70019
70369
|
if (n.isTieDestination && !n.tieOrigin.hasBend && !n.beat.hasWhammyBar) {
|
|
70020
|
-
const tie = new ScoreTieGlyph(n.tieOrigin, n, true);
|
|
70370
|
+
const tie = new ScoreTieGlyph(`score.tie.${n.tieOrigin.id}`, n.tieOrigin, n, true);
|
|
70021
70371
|
this.addTie(tie);
|
|
70022
70372
|
}
|
|
70023
70373
|
// TODO: depending on the type we have other positioning
|
|
@@ -70027,17 +70377,16 @@ class ScoreBeatContainerGlyph extends BeatContainerGlyph {
|
|
|
70027
70377
|
this.addTie(l);
|
|
70028
70378
|
}
|
|
70029
70379
|
if (n.isSlurOrigin && n.slurDestination && n.slurDestination.isVisible) {
|
|
70030
|
-
|
|
70031
|
-
const tie = new ScoreSlurGlyph(n, n.slurDestination, false);
|
|
70380
|
+
const tie = new ScoreSlurGlyph(`score.slur.${n.id}`, n, n.slurDestination, false);
|
|
70032
70381
|
this.addTie(tie);
|
|
70033
70382
|
}
|
|
70034
70383
|
if (n.isSlurDestination) {
|
|
70035
|
-
const tie = new ScoreSlurGlyph(n.slurOrigin, n, true);
|
|
70384
|
+
const tie = new ScoreSlurGlyph(`score.slur.${n.slurOrigin.id}`, n.slurOrigin, n, true);
|
|
70036
70385
|
this.addTie(tie);
|
|
70037
70386
|
}
|
|
70038
70387
|
// start effect slur on first beat
|
|
70039
70388
|
if (!this._effectSlur && n.isEffectSlurOrigin && n.effectSlurDestination) {
|
|
70040
|
-
const effectSlur = new ScoreSlurGlyph(n, n.effectSlurDestination, false);
|
|
70389
|
+
const effectSlur = new ScoreSlurGlyph(`score.slur.effect.${n.beat.id}`, n, n.effectSlurDestination, false);
|
|
70041
70390
|
this._effectSlur = effectSlur;
|
|
70042
70391
|
this.addTie(effectSlur);
|
|
70043
70392
|
}
|
|
@@ -70046,7 +70395,7 @@ class ScoreBeatContainerGlyph extends BeatContainerGlyph {
|
|
|
70046
70395
|
const direction = this.onNotes.beamingHelper.direction;
|
|
70047
70396
|
const startNote = direction === BeamDirection.Up ? n.beat.effectSlurOrigin.minNote : n.beat.effectSlurOrigin.maxNote;
|
|
70048
70397
|
const endNote = direction === BeamDirection.Up ? n.beat.minNote : n.beat.maxNote;
|
|
70049
|
-
const effectEndSlur = new ScoreSlurGlyph(startNote, endNote, true);
|
|
70398
|
+
const effectEndSlur = new ScoreSlurGlyph(`score.slur.effect.${startNote.beat.id}`, startNote, endNote, true);
|
|
70050
70399
|
this._effectEndSlur = effectEndSlur;
|
|
70051
70400
|
this.addTie(effectEndSlur);
|
|
70052
70401
|
}
|
|
@@ -70068,7 +70417,7 @@ class ScoreBeatContainerGlyph extends BeatContainerGlyph {
|
|
|
70068
70417
|
while (destination.nextBeat && destination.nextBeat.isLegatoDestination) {
|
|
70069
70418
|
destination = destination.nextBeat;
|
|
70070
70419
|
}
|
|
70071
|
-
this.addTie(new ScoreLegatoGlyph(this.beat, destination, false));
|
|
70420
|
+
this.addTie(new ScoreLegatoGlyph(`score.legato.${this.beat.id}`, this.beat, destination, false));
|
|
70072
70421
|
}
|
|
70073
70422
|
}
|
|
70074
70423
|
else if (this.beat.isLegatoDestination) {
|
|
@@ -70078,7 +70427,7 @@ class ScoreBeatContainerGlyph extends BeatContainerGlyph {
|
|
|
70078
70427
|
while (origin.previousBeat && origin.previousBeat.isLegatoOrigin) {
|
|
70079
70428
|
origin = origin.previousBeat;
|
|
70080
70429
|
}
|
|
70081
|
-
this.addTie(new ScoreLegatoGlyph(origin, this.beat, true));
|
|
70430
|
+
this.addTie(new ScoreLegatoGlyph(`score.legato.${origin.id}`, origin, this.beat, true));
|
|
70082
70431
|
}
|
|
70083
70432
|
}
|
|
70084
70433
|
}
|
|
@@ -70458,6 +70807,9 @@ class ScoreBarRenderer extends LineBarRenderer {
|
|
|
70458
70807
|
this.addBeatGlyph(container);
|
|
70459
70808
|
}
|
|
70460
70809
|
}
|
|
70810
|
+
getNoteLine(note) {
|
|
70811
|
+
return this.accidentalHelper.getNoteSteps(note) / 2;
|
|
70812
|
+
}
|
|
70461
70813
|
getNoteSteps(n) {
|
|
70462
70814
|
return this.accidentalHelper.getNoteSteps(n);
|
|
70463
70815
|
}
|
|
@@ -70514,43 +70866,15 @@ class ScoreBarRendererFactory extends BarRendererFactory {
|
|
|
70514
70866
|
/**
|
|
70515
70867
|
* @internal
|
|
70516
70868
|
*/
|
|
70517
|
-
class SlashTieGlyph extends
|
|
70518
|
-
|
|
70519
|
-
endNote;
|
|
70520
|
-
constructor(startNote, endNote, forEnd = false) {
|
|
70521
|
-
super(startNote.beat, endNote.beat, forEnd);
|
|
70522
|
-
this.startNote = startNote;
|
|
70523
|
-
this.endNote = endNote;
|
|
70524
|
-
}
|
|
70525
|
-
get _isLeftHandTap() {
|
|
70526
|
-
return this.startNote === this.endNote;
|
|
70527
|
-
}
|
|
70528
|
-
getTieHeight(startX, startY, endX, endY) {
|
|
70529
|
-
if (this._isLeftHandTap) {
|
|
70530
|
-
return this.startNoteRenderer.smuflMetrics.tieHeight;
|
|
70531
|
-
}
|
|
70532
|
-
return super.getTieHeight(startX, startY, endX, endY);
|
|
70533
|
-
}
|
|
70534
|
-
getBeamDirection(_beat, _noteRenderer) {
|
|
70535
|
-
return BeamDirection.Down;
|
|
70536
|
-
}
|
|
70537
|
-
static getBeamDirectionForNote(_note) {
|
|
70869
|
+
class SlashTieGlyph extends NoteTieGlyph {
|
|
70870
|
+
calculateTieDirection() {
|
|
70538
70871
|
return BeamDirection.Down;
|
|
70539
70872
|
}
|
|
70540
|
-
|
|
70541
|
-
return
|
|
70873
|
+
getStartNotePosition() {
|
|
70874
|
+
return NoteXPosition.Right;
|
|
70542
70875
|
}
|
|
70543
|
-
|
|
70544
|
-
return
|
|
70545
|
-
}
|
|
70546
|
-
getStartX() {
|
|
70547
|
-
if (this._isLeftHandTap) {
|
|
70548
|
-
return this.getEndX() - this.renderer.smuflMetrics.leftHandTabTieWidth;
|
|
70549
|
-
}
|
|
70550
|
-
return this.startNoteRenderer.getNoteX(this.startNote, NoteXPosition.Right);
|
|
70551
|
-
}
|
|
70552
|
-
getEndX() {
|
|
70553
|
-
return this.endNoteRenderer.getNoteX(this.endNote, NoteXPosition.Left);
|
|
70876
|
+
getEndNotePosition() {
|
|
70877
|
+
return NoteXPosition.Left;
|
|
70554
70878
|
}
|
|
70555
70879
|
}
|
|
70556
70880
|
|
|
@@ -70565,12 +70889,12 @@ class SlashBeatContainerGlyph extends BeatContainerGlyph {
|
|
|
70565
70889
|
return;
|
|
70566
70890
|
}
|
|
70567
70891
|
if (!this._tiedNoteTie && n.isTieOrigin && n.tieDestination.isVisible) {
|
|
70568
|
-
const tie = new SlashTieGlyph(n, n.tieDestination, false);
|
|
70892
|
+
const tie = new SlashTieGlyph('slash.tie', n, n.tieDestination, false);
|
|
70569
70893
|
this._tiedNoteTie = tie;
|
|
70570
70894
|
this.addTie(tie);
|
|
70571
70895
|
}
|
|
70572
70896
|
if (!this._tiedNoteTie && n.isTieDestination) {
|
|
70573
|
-
const tie = new SlashTieGlyph(n.tieOrigin, n, true);
|
|
70897
|
+
const tie = new SlashTieGlyph('slash.tie', n.tieOrigin, n, true);
|
|
70574
70898
|
this._tiedNoteTie = tie;
|
|
70575
70899
|
this.addTie(tie);
|
|
70576
70900
|
}
|
|
@@ -70697,8 +71021,7 @@ class SlashBeatGlyph extends BeatOnNoteGlyphBase {
|
|
|
70697
71021
|
doLayout() {
|
|
70698
71022
|
// create glyphs
|
|
70699
71023
|
const sr = this.renderer;
|
|
70700
|
-
const
|
|
70701
|
-
const glyphY = sr.getLineY(line);
|
|
71024
|
+
const glyphY = sr.getLineY(0);
|
|
70702
71025
|
if (this.container.beat.deadSlapped) {
|
|
70703
71026
|
const deadSlapped = new DeadSlappedBeatGlyph();
|
|
70704
71027
|
deadSlapped.renderer = this.renderer;
|
|
@@ -70731,7 +71054,7 @@ class SlashBeatGlyph extends BeatOnNoteGlyphBase {
|
|
|
70731
71054
|
//
|
|
70732
71055
|
if (this.container.beat.dots > 0) {
|
|
70733
71056
|
for (let i = 0; i < this.container.beat.dots; i++) {
|
|
70734
|
-
this.addEffect(new AugmentationDotGlyph(0,
|
|
71057
|
+
this.addEffect(new AugmentationDotGlyph(0, glyphY - sr.getLineHeight(0.5)));
|
|
70735
71058
|
}
|
|
70736
71059
|
}
|
|
70737
71060
|
super.doLayout();
|
|
@@ -70813,7 +71136,7 @@ class SlashBarRenderer extends LineBarRenderer {
|
|
|
70813
71136
|
this.registerOverflowTop(this.tupletSize);
|
|
70814
71137
|
}
|
|
70815
71138
|
}
|
|
70816
|
-
getNoteLine() {
|
|
71139
|
+
getNoteLine(_note) {
|
|
70817
71140
|
return 0;
|
|
70818
71141
|
}
|
|
70819
71142
|
getFlagTopY(beat, _direction) {
|
|
@@ -71150,77 +71473,6 @@ class TabSlideLineGlyph extends Glyph {
|
|
|
71150
71473
|
}
|
|
71151
71474
|
}
|
|
71152
71475
|
|
|
71153
|
-
/**
|
|
71154
|
-
* @internal
|
|
71155
|
-
*/
|
|
71156
|
-
class TabSlurGlyph extends TabTieGlyph {
|
|
71157
|
-
_direction;
|
|
71158
|
-
_forSlide;
|
|
71159
|
-
constructor(startNote, endNote, forSlide, forEnd = false) {
|
|
71160
|
-
super(startNote, endNote, forEnd);
|
|
71161
|
-
this._direction = TabTieGlyph.getBeamDirectionForNote(startNote);
|
|
71162
|
-
this._forSlide = forSlide;
|
|
71163
|
-
}
|
|
71164
|
-
getTieHeight(startX, _startY, endX, _endY) {
|
|
71165
|
-
return Math.log(endX - startX + 1) * this.renderer.settings.notation.slurHeight / 2;
|
|
71166
|
-
}
|
|
71167
|
-
tryExpand(startNote, endNote, forSlide, forEnd) {
|
|
71168
|
-
// same type required
|
|
71169
|
-
if (this._forSlide !== forSlide) {
|
|
71170
|
-
return false;
|
|
71171
|
-
}
|
|
71172
|
-
if (this.forEnd !== forEnd) {
|
|
71173
|
-
return false;
|
|
71174
|
-
}
|
|
71175
|
-
// same start and endbeat
|
|
71176
|
-
if (this.startNote.beat.id !== startNote.beat.id) {
|
|
71177
|
-
return false;
|
|
71178
|
-
}
|
|
71179
|
-
if (this.endNote.beat.id !== endNote.beat.id) {
|
|
71180
|
-
return false;
|
|
71181
|
-
}
|
|
71182
|
-
// same draw direction
|
|
71183
|
-
if (this._direction !== TabTieGlyph.getBeamDirectionForNote(startNote)) {
|
|
71184
|
-
return false;
|
|
71185
|
-
}
|
|
71186
|
-
// if we can expand, expand in correct direction
|
|
71187
|
-
switch (this._direction) {
|
|
71188
|
-
case BeamDirection.Up:
|
|
71189
|
-
if (startNote.realValue > this.startNote.realValue) {
|
|
71190
|
-
this.startNote = startNote;
|
|
71191
|
-
this.startBeat = startNote.beat;
|
|
71192
|
-
}
|
|
71193
|
-
if (endNote.realValue > this.endNote.realValue) {
|
|
71194
|
-
this.endNote = endNote;
|
|
71195
|
-
this.endBeat = endNote.beat;
|
|
71196
|
-
}
|
|
71197
|
-
break;
|
|
71198
|
-
case BeamDirection.Down:
|
|
71199
|
-
if (startNote.realValue < this.startNote.realValue) {
|
|
71200
|
-
this.startNote = startNote;
|
|
71201
|
-
this.startBeat = startNote.beat;
|
|
71202
|
-
}
|
|
71203
|
-
if (endNote.realValue < this.endNote.realValue) {
|
|
71204
|
-
this.endNote = endNote;
|
|
71205
|
-
this.endBeat = endNote.beat;
|
|
71206
|
-
}
|
|
71207
|
-
break;
|
|
71208
|
-
}
|
|
71209
|
-
return true;
|
|
71210
|
-
}
|
|
71211
|
-
paint(cx, cy, canvas) {
|
|
71212
|
-
const startNoteRenderer = this.renderer.scoreRenderer.layout.getRendererForBar(this.renderer.staff.staffId, this.startBeat.voice.bar);
|
|
71213
|
-
const direction = this.getBeamDirection(this.startBeat, startNoteRenderer);
|
|
71214
|
-
const slurId = `tab.slur.${this.startNote.beat.id}.${this.endNote.beat.id}.${direction}`;
|
|
71215
|
-
const renderer = this.renderer;
|
|
71216
|
-
const isSlurRendered = renderer.staff.getSharedLayoutData(slurId, false);
|
|
71217
|
-
if (!isSlurRendered) {
|
|
71218
|
-
renderer.staff.setSharedLayoutData(slurId, true);
|
|
71219
|
-
super.paint(cx, cy, canvas);
|
|
71220
|
-
}
|
|
71221
|
-
}
|
|
71222
|
-
}
|
|
71223
|
-
|
|
71224
71476
|
/**
|
|
71225
71477
|
* @internal
|
|
71226
71478
|
*/
|
|
@@ -71245,15 +71497,15 @@ class TabBeatContainerGlyph extends BeatContainerGlyph {
|
|
|
71245
71497
|
}
|
|
71246
71498
|
const renderer = this.renderer;
|
|
71247
71499
|
if (n.isTieOrigin && renderer.showTiedNotes && n.tieDestination.isVisible) {
|
|
71248
|
-
const tie = new TabTieGlyph(n, n.tieDestination, false);
|
|
71500
|
+
const tie = new TabTieGlyph(`tab.tie.${n.id}`, n, n.tieDestination, false);
|
|
71249
71501
|
this.addTie(tie);
|
|
71250
71502
|
}
|
|
71251
71503
|
if (n.isTieDestination && renderer.showTiedNotes) {
|
|
71252
|
-
const tie = new TabTieGlyph(n.tieOrigin, n, true);
|
|
71504
|
+
const tie = new TabTieGlyph(`tab.tie.${n.tieOrigin.id}`, n.tieOrigin, n, true);
|
|
71253
71505
|
this.addTie(tie);
|
|
71254
71506
|
}
|
|
71255
71507
|
if (n.isLeftHandTapped && !n.isHammerPullDestination) {
|
|
71256
|
-
const tapSlur = new TabTieGlyph(n, n, false);
|
|
71508
|
+
const tapSlur = new TabTieGlyph(`tab.tie.leftHandTap.${n.id}`, n, n, false);
|
|
71257
71509
|
this.addTie(tapSlur);
|
|
71258
71510
|
}
|
|
71259
71511
|
// start effect slur on first beat
|
|
@@ -71266,7 +71518,7 @@ class TabBeatContainerGlyph extends BeatContainerGlyph {
|
|
|
71266
71518
|
}
|
|
71267
71519
|
}
|
|
71268
71520
|
if (!expanded) {
|
|
71269
|
-
const effectSlur = new TabSlurGlyph(n, n.effectSlurDestination, false, false);
|
|
71521
|
+
const effectSlur = new TabSlurGlyph(`tab.slur.effect.${n.id}`, n, n.effectSlurDestination, false, false);
|
|
71270
71522
|
this._effectSlurs.push(effectSlur);
|
|
71271
71523
|
this.addTie(effectSlur);
|
|
71272
71524
|
}
|
|
@@ -71281,7 +71533,7 @@ class TabBeatContainerGlyph extends BeatContainerGlyph {
|
|
|
71281
71533
|
}
|
|
71282
71534
|
}
|
|
71283
71535
|
if (!expanded) {
|
|
71284
|
-
const effectSlur = new TabSlurGlyph(n.effectSlurOrigin, n, false, true);
|
|
71536
|
+
const effectSlur = new TabSlurGlyph(`tab.slur.effect.${n.effectSlurOrigin.id}`, n.effectSlurOrigin, n, false, true);
|
|
71285
71537
|
this._effectSlurs.push(effectSlur);
|
|
71286
71538
|
this.addTie(effectSlur);
|
|
71287
71539
|
}
|
|
@@ -71700,7 +71952,7 @@ class TabBeatGlyph extends BeatOnNoteGlyphBase {
|
|
|
71700
71952
|
}
|
|
71701
71953
|
else {
|
|
71702
71954
|
const line = Math.floor((this.renderer.bar.staff.tuning.length - 1) / 2);
|
|
71703
|
-
const y = tabRenderer.
|
|
71955
|
+
const y = tabRenderer.getLineY(line);
|
|
71704
71956
|
const restGlyph = new TabRestGlyph(0, y, tabRenderer.showRests, this.container.beat.duration);
|
|
71705
71957
|
this.restGlyph = restGlyph;
|
|
71706
71958
|
restGlyph.beat = this.container.beat;
|
|
@@ -71759,8 +72011,8 @@ class TabBeatGlyph extends BeatOnNoteGlyphBase {
|
|
|
71759
72011
|
_createNoteGlyph(n) {
|
|
71760
72012
|
const tr = this.renderer;
|
|
71761
72013
|
const noteNumberGlyph = new NoteNumberGlyph(0, 0, n);
|
|
71762
|
-
const l =
|
|
71763
|
-
noteNumberGlyph.y = tr.
|
|
72014
|
+
const l = tr.getNoteLine(n);
|
|
72015
|
+
noteNumberGlyph.y = tr.getLineY(l);
|
|
71764
72016
|
noteNumberGlyph.renderer = this.renderer;
|
|
71765
72017
|
noteNumberGlyph.doLayout();
|
|
71766
72018
|
this.noteNumbers.addNoteGlyph(noteNumberGlyph, n);
|
|
@@ -71951,17 +72203,8 @@ class TabBarRenderer extends LineBarRenderer {
|
|
|
71951
72203
|
}
|
|
71952
72204
|
return mode;
|
|
71953
72205
|
}
|
|
71954
|
-
|
|
71955
|
-
|
|
71956
|
-
* @param line the line of the particular string where 0 is the most top line
|
|
71957
|
-
* @param correction
|
|
71958
|
-
* @returns
|
|
71959
|
-
*/
|
|
71960
|
-
getTabY(line) {
|
|
71961
|
-
return super.getLineY(line);
|
|
71962
|
-
}
|
|
71963
|
-
getTabHeight(line) {
|
|
71964
|
-
return super.getLineHeight(line);
|
|
72206
|
+
getNoteLine(note) {
|
|
72207
|
+
return this.bar.staff.tuning.length - note.string;
|
|
71965
72208
|
}
|
|
71966
72209
|
minString = Number.NaN;
|
|
71967
72210
|
maxString = Number.NaN;
|
|
@@ -72050,7 +72293,7 @@ class TabBarRenderer extends LineBarRenderer {
|
|
|
72050
72293
|
if (this.isFirstOfLine) {
|
|
72051
72294
|
const center = (this.bar.staff.tuning.length - 1) / 2;
|
|
72052
72295
|
this.createStartSpacing();
|
|
72053
|
-
this.addPreBeatGlyph(new TabClefGlyph(0, this.
|
|
72296
|
+
this.addPreBeatGlyph(new TabClefGlyph(0, this.getLineY(center)));
|
|
72054
72297
|
}
|
|
72055
72298
|
// Time Signature
|
|
72056
72299
|
if (this.showTimeSignature &&
|
|
@@ -72071,7 +72314,7 @@ class TabBarRenderer extends LineBarRenderer {
|
|
|
72071
72314
|
_createTimeSignatureGlyphs() {
|
|
72072
72315
|
this.addPreBeatGlyph(new SpacingGlyph(0, 0, this.smuflMetrics.oneStaffSpace));
|
|
72073
72316
|
const lines = (this.bar.staff.tuning.length + 1) / 2 - 1;
|
|
72074
|
-
this.addPreBeatGlyph(new TabTimeSignatureGlyph(0, this.
|
|
72317
|
+
this.addPreBeatGlyph(new TabTimeSignatureGlyph(0, this.getLineY(lines), this.bar.masterBar.timeSignatureNumerator, this.bar.masterBar.timeSignatureDenominator, this.bar.masterBar.timeSignatureCommon, this.bar.masterBar.isFreeTime));
|
|
72075
72318
|
}
|
|
72076
72319
|
createVoiceGlyphs(v) {
|
|
72077
72320
|
super.createVoiceGlyphs(v);
|