@coderline/alphatab 1.3.0-alpha.138 → 1.3.0-alpha.142

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.js CHANGED
@@ -1,7 +1,7 @@
1
1
  /**
2
- * alphaTab v1.3.0-alpha.138 (develop, build 138)
2
+ * alphaTab v1.3.0-alpha.142 (develop, build 142)
3
3
  *
4
- * Copyright © 2021, Daniel Kuschny and Contributors, All rights reserved.
4
+ * Copyright © 2022, Daniel Kuschny and Contributors, All rights reserved.
5
5
  *
6
6
  * This Source Code Form is subject to the terms of the Mozilla Public
7
7
  * License, v. 2.0. If a copy of the MPL was not distributed with this
@@ -138,7 +138,7 @@
138
138
  })(exports.AlphaTabErrorType || (exports.AlphaTabErrorType = {}));
139
139
  class AlphaTabError extends Error {
140
140
  constructor(type, message = "", inner) {
141
- super(message);
141
+ super(message !== null && message !== void 0 ? message : "");
142
142
  this.type = type;
143
143
  this.inner = inner !== null && inner !== void 0 ? inner : null;
144
144
  Object.setPrototypeOf(this, AlphaTabError.prototype);
@@ -150,8 +150,8 @@
150
150
  * binary data does not contain a reader compatible structure.
151
151
  */
152
152
  class UnsupportedFormatError extends AlphaTabError {
153
- constructor(message = 'Unsupported format', inner = null) {
154
- super(exports.AlphaTabErrorType.Format, message);
153
+ constructor(message = null, inner = null) {
154
+ super(exports.AlphaTabErrorType.Format, message !== null && message !== void 0 ? message : 'Unsupported format');
155
155
  this.inner = inner;
156
156
  Object.setPrototypeOf(this, UnsupportedFormatError.prototype);
157
157
  }
@@ -202,6 +202,7 @@
202
202
  * Automations are used to change the behaviour of a song.
203
203
  * @cloneable
204
204
  * @json
205
+ * @json_strict
205
206
  */
206
207
  class Automation {
207
208
  constructor() {
@@ -330,6 +331,7 @@
330
331
  /**
331
332
  * A bar is a single block within a track, also known as Measure.
332
333
  * @json
334
+ * @json_strict
333
335
  */
334
336
  class Bar {
335
337
  constructor() {
@@ -391,11 +393,11 @@
391
393
  voice.index = this.voices.length;
392
394
  this.voices.push(voice);
393
395
  }
394
- finish(settings) {
396
+ finish(settings, sharedDataBag) {
395
397
  this.isMultiVoice = false;
396
398
  for (let i = 0, j = this.voices.length; i < j; i++) {
397
399
  let voice = this.voices[i];
398
- voice.finish(settings);
400
+ voice.finish(settings, sharedDataBag);
399
401
  if (i > 0 && !voice.isEmpty) {
400
402
  this.isMultiVoice = true;
401
403
  }
@@ -475,6 +477,7 @@
475
477
  * describe WhammyBar and String Bending effects.
476
478
  * @cloneable
477
479
  * @json
480
+ * @json_strict
478
481
  */
479
482
  class BendPoint {
480
483
  /**
@@ -1742,6 +1745,7 @@
1742
1745
  /**
1743
1746
  * Describes an instrument articulation which is used for percussions.
1744
1747
  * @json
1748
+ * @json_strict
1745
1749
  */
1746
1750
  class InstrumentArticulation {
1747
1751
  constructor(elementType = "", staffLine = 0, outputMidiNumber = 0, noteHeadDefault = MusicFontSymbol.None, noteHeadHalf = MusicFontSymbol.None, noteHeadWhole = MusicFontSymbol.None, techniqueSymbol = MusicFontSymbol.None, techniqueSymbolPlacement = TextBaseline.Middle) {
@@ -1963,12 +1967,23 @@
1963
1967
  [34, new InstrumentArticulation("snare", 3, 38, MusicFontSymbol.NoteheadBlack, MusicFontSymbol.NoteheadBlack, MusicFontSymbol.NoteheadBlack)]
1964
1968
  ]);
1965
1969
 
1970
+ class NoteIdBag {
1971
+ constructor() {
1972
+ this.tieDestinationNoteId = -1;
1973
+ this.tieOriginNoteId = -1;
1974
+ this.slurDestinationNoteId = -1;
1975
+ this.slurOriginNoteId = -1;
1976
+ this.hammerPullDestinationNoteId = -1;
1977
+ this.hammerPullOriginNoteId = -1;
1978
+ }
1979
+ }
1966
1980
  /**
1967
1981
  * A note is a single played sound on a fretted instrument.
1968
1982
  * It consists of a fret offset and a string on which the note is played on.
1969
1983
  * It also can be modified by a lot of different effects.
1970
1984
  * @cloneable
1971
1985
  * @json
1986
+ * @json_strict
1972
1987
  */
1973
1988
  class Note {
1974
1989
  constructor() {
@@ -2009,7 +2024,7 @@
2009
2024
  * @clone_add addBendPoint
2010
2025
  * @json_add addBendPoint
2011
2026
  */
2012
- this.bendPoints = [];
2027
+ this.bendPoints = null;
2013
2028
  /**
2014
2029
  * Gets or sets the bend point with the highest bend value.
2015
2030
  * @clone_ignore
@@ -2147,25 +2162,33 @@
2147
2162
  */
2148
2163
  this.isHammerPullOrigin = false;
2149
2164
  /**
2150
- * Gets the origin note id of the hammeron/pull-off of this note.
2165
+ * Gets the origin of the hammeron/pulloff of this note.
2166
+ * @clone_ignore
2167
+ * @json_ignore
2151
2168
  */
2152
- this.hammerPullOriginNoteId = -1;
2169
+ this.hammerPullOrigin = null;
2153
2170
  /**
2154
- * Gets the destination note id of the hammeron/pull-off of this note.
2171
+ * Gets the destination for the hammeron/pullof started by this note.
2172
+ * @clone_ignore
2173
+ * @json_ignore
2155
2174
  */
2156
- this.hammerPullDestinationNoteId = -1;
2175
+ this.hammerPullDestination = null;
2157
2176
  /**
2158
2177
  * Gets or sets whether this note finishes a slur.
2159
2178
  */
2160
2179
  this.isSlurDestination = false;
2161
2180
  /**
2162
- * Gets the note id where the slur of this note starts.
2181
+ * Gets or sets the note where the slur of this note starts.
2182
+ * @clone_ignore
2183
+ * @json_ignore
2163
2184
  */
2164
- this.slurOriginNoteId = -1;
2185
+ this.slurOrigin = null;
2165
2186
  /**
2166
- * Gets or sets the note id where the slur of this note ends.
2187
+ * Gets or sets the note where the slur of this note ends.
2188
+ * @clone_ignore
2189
+ * @json_ignore
2167
2190
  */
2168
- this.slurDestinationNoteId = -1;
2191
+ this.slurDestination = null;
2169
2192
  /**
2170
2193
  * Gets or sets the harmonic type applied to this note.
2171
2194
  */
@@ -2231,13 +2254,17 @@
2231
2254
  */
2232
2255
  this.vibrato = VibratoType.None;
2233
2256
  /**
2234
- * Gets the origin note id of the tied if this note is tied.
2257
+ * Gets the origin of the tied if this note is tied.
2258
+ * @clone_ignore
2259
+ * @json_ignore
2235
2260
  */
2236
- this.tieOriginNoteId = -1;
2261
+ this.tieOrigin = null;
2237
2262
  /**
2238
- * Gets the desination note id of the tie.
2263
+ * Gets the desination of the tie.
2264
+ * @clone_ignore
2265
+ * @json_ignore
2239
2266
  */
2240
- this.tieDestinationNoteId = -1;
2267
+ this.tieDestination = null;
2241
2268
  /**
2242
2269
  * Gets or sets whether this note is ends a tied note.
2243
2270
  */
@@ -2294,9 +2321,10 @@
2294
2321
  * @json_ignore
2295
2322
  */
2296
2323
  this.effectSlurDestination = null;
2324
+ this._noteIdBag = null;
2297
2325
  }
2298
2326
  get hasBend() {
2299
- return this.bendType !== BendType.None;
2327
+ return this.bendPoints !== null && this.bendType !== BendType.None;
2300
2328
  }
2301
2329
  get isStringed() {
2302
2330
  return this.string >= 0;
@@ -2324,50 +2352,14 @@
2324
2352
  get isHammerPullDestination() {
2325
2353
  return !!this.hammerPullOrigin;
2326
2354
  }
2327
- /**
2328
- * Gets the origin of the hammeron/pulloff of this note.
2329
- */
2330
- get hammerPullOrigin() {
2331
- return this.hammerPullOriginNoteId === -1 ? null : this.beat.voice.bar.staff.track.score.getNoteById(this.hammerPullOriginNoteId);
2332
- }
2333
- /**
2334
- * Gets the destination for the hammeron/pullof started by this note.
2335
- */
2336
- get hammerPullDestination() {
2337
- return this.hammerPullDestinationNoteId === -1 ? null : this.beat.voice.bar.staff.track.score.getNoteById(this.hammerPullDestinationNoteId);
2338
- }
2339
2355
  get isSlurOrigin() {
2340
2356
  return !!this.slurDestination;
2341
2357
  }
2342
- /**
2343
- * Gets or sets the note where the slur of this note starts.
2344
- */
2345
- get slurOrigin() {
2346
- return this.slurOriginNoteId === -1 ? null : this.beat.voice.bar.staff.track.score.getNoteById(this.slurOriginNoteId);
2347
- }
2348
- /**
2349
- * Gets or sets the note where the slur of this note ends.
2350
- */
2351
- get slurDestination() {
2352
- return this.slurDestinationNoteId === -1 ? null : this.beat.voice.bar.staff.track.score.getNoteById(this.slurDestinationNoteId);
2353
- }
2354
2358
  get isHarmonic() {
2355
2359
  return this.harmonicType !== HarmonicType.None;
2356
2360
  }
2357
- /**
2358
- * Gets the origin of the tied if this note is tied.
2359
- */
2360
- get tieOrigin() {
2361
- return this.tieOriginNoteId === -1 ? null : this.beat.voice.bar.staff.track.score.getNoteById(this.tieOriginNoteId);
2362
- }
2363
- /**
2364
- * Gets the desination of the tie.
2365
- */
2366
- get tieDestination() {
2367
- return this.tieDestinationNoteId === -1 ? null : this.beat.voice.bar.staff.track.score.getNoteById(this.tieDestinationNoteId);
2368
- }
2369
2361
  get isTieOrigin() {
2370
- return this.tieDestinationNoteId !== -1;
2362
+ return this.tieDestination !== null;
2371
2363
  }
2372
2364
  get trillFret() {
2373
2365
  return this.trillValue - this.stringTuning;
@@ -2568,7 +2560,12 @@
2568
2560
  return false;
2569
2561
  }
2570
2562
  addBendPoint(point) {
2571
- this.bendPoints.push(point);
2563
+ let points = this.bendPoints;
2564
+ if (points === null) {
2565
+ points = [];
2566
+ this.bendPoints = points;
2567
+ }
2568
+ points.push(point);
2572
2569
  if (!this.maxBendPoint || point.value > this.maxBendPoint.value) {
2573
2570
  this.maxBendPoint = point;
2574
2571
  }
@@ -2576,12 +2573,12 @@
2576
2573
  this.bendType = BendType.Custom;
2577
2574
  }
2578
2575
  }
2579
- finish(settings) {
2576
+ finish(settings, sharedDataBag) {
2580
2577
  let nextNoteOnLine = new Lazy(() => Note.nextNoteOnSameLine(this));
2581
2578
  let isSongBook = settings && settings.notation.notationMode === exports.NotationMode.SongBook;
2582
2579
  // connect ties
2583
2580
  if (this.isTieDestination) {
2584
- this.chain();
2581
+ this.chain(sharedDataBag);
2585
2582
  // implicit let ring
2586
2583
  if (isSongBook && this.tieOrigin && this.tieOrigin.isLetRing) {
2587
2584
  this.isLetRing = true;
@@ -2615,8 +2612,8 @@
2615
2612
  this.isHammerPullOrigin = false;
2616
2613
  }
2617
2614
  else {
2618
- this.hammerPullDestinationNoteId = hammerPullDestination.id;
2619
- hammerPullDestination.hammerPullOriginNoteId = this.id;
2615
+ this.hammerPullDestination = hammerPullDestination;
2616
+ hammerPullDestination.hammerPullOrigin = this;
2620
2617
  }
2621
2618
  }
2622
2619
  // set slides
@@ -2654,14 +2651,15 @@
2654
2651
  }
2655
2652
  // try to detect what kind of bend was used and cleans unneeded points if required
2656
2653
  // Guitar Pro 6 and above (gpif.xml) uses exactly 4 points to define all bends
2657
- if (this.bendPoints.length > 0 && this.bendType === BendType.Custom) {
2654
+ const points = this.bendPoints;
2655
+ if (points != null && points.length > 0 && this.bendType === BendType.Custom) {
2658
2656
  let isContinuedBend = this.isTieDestination && this.tieOrigin.hasBend;
2659
2657
  this.isContinuedBend = isContinuedBend;
2660
- if (this.bendPoints.length === 4) {
2661
- let origin = this.bendPoints[0];
2662
- let middle1 = this.bendPoints[1];
2663
- let middle2 = this.bendPoints[2];
2664
- let destination = this.bendPoints[3];
2658
+ if (points.length === 4) {
2659
+ let origin = points[0];
2660
+ let middle1 = points[1];
2661
+ let middle2 = points[2];
2662
+ let destination = points[3];
2665
2663
  // the middle points are used for holds, anything else is a new feature we do not support yet
2666
2664
  if (middle1.value === middle2.value) {
2667
2665
  // bend higher?
@@ -2671,26 +2669,26 @@
2671
2669
  }
2672
2670
  else if (!isContinuedBend && origin.value > 0) {
2673
2671
  this.bendType = BendType.PrebendBend;
2674
- this.bendPoints.splice(2, 1);
2675
- this.bendPoints.splice(1, 1);
2672
+ points.splice(2, 1);
2673
+ points.splice(1, 1);
2676
2674
  }
2677
2675
  else {
2678
2676
  this.bendType = BendType.Bend;
2679
- this.bendPoints.splice(2, 1);
2680
- this.bendPoints.splice(1, 1);
2677
+ points.splice(2, 1);
2678
+ points.splice(1, 1);
2681
2679
  }
2682
2680
  }
2683
2681
  else if (destination.value < origin.value) {
2684
2682
  // origin must be > 0 otherwise it's no release, we cannot bend negative
2685
2683
  if (isContinuedBend) {
2686
2684
  this.bendType = BendType.Release;
2687
- this.bendPoints.splice(2, 1);
2688
- this.bendPoints.splice(1, 1);
2685
+ points.splice(2, 1);
2686
+ points.splice(1, 1);
2689
2687
  }
2690
2688
  else {
2691
2689
  this.bendType = BendType.PrebendRelease;
2692
- this.bendPoints.splice(2, 1);
2693
- this.bendPoints.splice(1, 1);
2690
+ points.splice(2, 1);
2691
+ points.splice(1, 1);
2694
2692
  }
2695
2693
  }
2696
2694
  else {
@@ -2699,13 +2697,13 @@
2699
2697
  }
2700
2698
  else if (origin.value > 0 && !isContinuedBend) {
2701
2699
  this.bendType = BendType.Prebend;
2702
- this.bendPoints.splice(2, 1);
2703
- this.bendPoints.splice(1, 1);
2700
+ points.splice(2, 1);
2701
+ points.splice(1, 1);
2704
2702
  }
2705
2703
  else {
2706
2704
  this.bendType = BendType.Hold;
2707
- this.bendPoints.splice(2, 1);
2708
- this.bendPoints.splice(1, 1);
2705
+ points.splice(2, 1);
2706
+ points.splice(1, 1);
2709
2707
  }
2710
2708
  }
2711
2709
  }
@@ -2713,9 +2711,9 @@
2713
2711
  Logger.warning('Model', 'Unsupported bend type detected, fallback to custom', null);
2714
2712
  }
2715
2713
  }
2716
- else if (this.bendPoints.length === 2) {
2717
- let origin = this.bendPoints[0];
2718
- let destination = this.bendPoints[1];
2714
+ else if (points.length === 2) {
2715
+ let origin = points[0];
2716
+ let destination = points[1];
2719
2717
  // bend higher?
2720
2718
  if (destination.value > origin.value) {
2721
2719
  if (!isContinuedBend && origin.value > 0) {
@@ -2739,7 +2737,7 @@
2739
2737
  }
2740
2738
  }
2741
2739
  }
2742
- else if (this.bendPoints.length === 0) {
2740
+ else if (points === null || points.length === 0) {
2743
2741
  this.bendType = BendType.None;
2744
2742
  }
2745
2743
  // initial bend pitch offsets and forced accidentals don't play well together
@@ -2835,35 +2833,134 @@
2835
2833
  }
2836
2834
  return null;
2837
2835
  }
2838
- chain() {
2839
- this.beat.voice.bar.staff.track.score.registerNote(this);
2840
- if (!this.isTieDestination) {
2841
- return;
2842
- }
2843
- let tieOrigin;
2844
- if (this.tieOriginNoteId === -1) {
2845
- tieOrigin = Note.findTieOrigin(this);
2846
- this.tieOriginNoteId = tieOrigin ? tieOrigin.id : -1;
2836
+ chain(sharedDataBag) {
2837
+ // if we have some IDs from a serialization flow,
2838
+ // we need to lookup/register the notes correctly
2839
+ if (this._noteIdBag != null) {
2840
+ // get or create lookup
2841
+ let noteIdLookup;
2842
+ if (sharedDataBag.has(Note.NoteIdLookupKey)) {
2843
+ noteIdLookup = sharedDataBag.get(Note.NoteIdLookupKey);
2844
+ }
2845
+ else {
2846
+ noteIdLookup = new Map();
2847
+ sharedDataBag.set(Note.NoteIdLookupKey, noteIdLookup);
2848
+ }
2849
+ // if this note is a source note for any effect, remember it for later
2850
+ // the destination note will look it up for linking
2851
+ if (this._noteIdBag.hammerPullDestinationNoteId !== -1 ||
2852
+ this._noteIdBag.tieDestinationNoteId !== -1 ||
2853
+ this._noteIdBag.slurDestinationNoteId !== -1) {
2854
+ noteIdLookup.set(this.id, this);
2855
+ }
2856
+ // on any effect destiniation, lookup the origin which should already be
2857
+ // registered
2858
+ if (this._noteIdBag.hammerPullOriginNoteId !== -1) {
2859
+ this.hammerPullOrigin = noteIdLookup.get(this._noteIdBag.hammerPullOriginNoteId);
2860
+ this.hammerPullOrigin.hammerPullDestination = this;
2861
+ }
2862
+ if (this._noteIdBag.tieOriginNoteId !== -1) {
2863
+ this.tieOrigin = noteIdLookup.get(this._noteIdBag.tieOriginNoteId);
2864
+ this.tieOrigin.tieDestination = this;
2865
+ }
2866
+ if (this._noteIdBag.slurOriginNoteId !== -1) {
2867
+ this.slurOrigin = noteIdLookup.get(this._noteIdBag.slurOriginNoteId);
2868
+ this.slurOrigin.slurDestination = this;
2869
+ }
2870
+ this._noteIdBag = null; // not needed anymore
2847
2871
  }
2848
2872
  else {
2849
- tieOrigin = this.tieOrigin;
2873
+ if (!this.isTieDestination && this.tieOrigin == null) {
2874
+ return;
2875
+ }
2876
+ let tieOrigin = Note.findTieOrigin(this);
2877
+ if (!tieOrigin) {
2878
+ this.isTieDestination = false;
2879
+ }
2880
+ else {
2881
+ tieOrigin.tieDestination = this;
2882
+ this.tieOrigin = tieOrigin;
2883
+ this.fret = tieOrigin.fret;
2884
+ this.octave = tieOrigin.octave;
2885
+ this.tone = tieOrigin.tone;
2886
+ if (tieOrigin.hasBend) {
2887
+ this.bendOrigin = this.tieOrigin;
2888
+ }
2889
+ }
2850
2890
  }
2851
- if (!tieOrigin) {
2852
- this.isTieDestination = false;
2891
+ }
2892
+ /**
2893
+ * @internal
2894
+ */
2895
+ toJson(o) {
2896
+ // inject linked note ids into JSON
2897
+ if (this.tieDestination !== null) {
2898
+ o.set("tiedestinationnoteid", this.tieDestination.id);
2853
2899
  }
2854
- else {
2855
- tieOrigin.tieDestinationNoteId = this.id;
2856
- this.fret = tieOrigin.fret;
2857
- this.octave = tieOrigin.octave;
2858
- this.tone = tieOrigin.tone;
2859
- if (tieOrigin.hasBend) {
2860
- this.bendOrigin = this.tieOrigin;
2861
- }
2900
+ if (this.tieOrigin !== null) {
2901
+ o.set("tieoriginnoteid", this.tieOrigin.id);
2902
+ }
2903
+ if (this.slurDestination !== null) {
2904
+ o.set("slurdestinationnoteid", this.slurDestination.id);
2905
+ }
2906
+ if (this.slurOrigin !== null) {
2907
+ o.set("sluroriginnoteid", this.slurOrigin.id);
2908
+ }
2909
+ if (this.hammerPullOrigin !== null) {
2910
+ o.set("hammerpulloriginnoteid", this.hammerPullOrigin.id);
2911
+ }
2912
+ if (this.hammerPullDestination !== null) {
2913
+ o.set("hammerpulldestinationnoteid", this.hammerPullDestination.id);
2862
2914
  }
2863
2915
  }
2916
+ /**
2917
+ * @internal
2918
+ */
2919
+ setProperty(property, v) {
2920
+ switch (property) {
2921
+ case "tiedestinationnoteid":
2922
+ if (this._noteIdBag == null) {
2923
+ this._noteIdBag = new NoteIdBag();
2924
+ }
2925
+ this._noteIdBag.tieDestinationNoteId = v;
2926
+ return true;
2927
+ case "tieoriginnoteid":
2928
+ if (this._noteIdBag == null) {
2929
+ this._noteIdBag = new NoteIdBag();
2930
+ }
2931
+ this._noteIdBag.tieOriginNoteId = v;
2932
+ return true;
2933
+ case "slurdestinationnoteid":
2934
+ if (this._noteIdBag == null) {
2935
+ this._noteIdBag = new NoteIdBag();
2936
+ }
2937
+ this._noteIdBag.slurDestinationNoteId = v;
2938
+ return true;
2939
+ case "sluroriginnoteid":
2940
+ if (this._noteIdBag == null) {
2941
+ this._noteIdBag = new NoteIdBag();
2942
+ }
2943
+ this._noteIdBag.slurOriginNoteId = v;
2944
+ return true;
2945
+ case "hammerpulloriginnoteid":
2946
+ if (this._noteIdBag == null) {
2947
+ this._noteIdBag = new NoteIdBag();
2948
+ }
2949
+ this._noteIdBag.hammerPullOriginNoteId = v;
2950
+ return true;
2951
+ case "hammerpulldestinationnoteid":
2952
+ if (this._noteIdBag == null) {
2953
+ this._noteIdBag = new NoteIdBag();
2954
+ }
2955
+ this._noteIdBag.hammerPullDestinationNoteId = v;
2956
+ return true;
2957
+ }
2958
+ return false;
2959
+ }
2864
2960
  }
2865
2961
  Note.GlobalNoteId = 0;
2866
- Note.MaxOffsetForSameLineSearch = 3;
2962
+ Note.MaxOffsetForSameLineSearch = 3;
2963
+ Note.NoteIdLookupKey = "NoteIdLookup";
2867
2964
 
2868
2965
  /**
2869
2966
  * Represents a list of beats that are grouped within the same tuplet.
@@ -3009,9 +3106,11 @@
3009
3106
  clone.bendType = original.bendType;
3010
3107
  clone.bendStyle = original.bendStyle;
3011
3108
  clone.isContinuedBend = original.isContinuedBend;
3012
- clone.bendPoints = [];
3013
- for (const i of original.bendPoints) {
3014
- clone.addBendPoint(BendPointCloner.clone(i));
3109
+ if (original.bendPoints) {
3110
+ clone.bendPoints = [];
3111
+ for (const i of original.bendPoints) {
3112
+ clone.addBendPoint(BendPointCloner.clone(i));
3113
+ }
3015
3114
  }
3016
3115
  clone.fret = original.fret;
3017
3116
  clone.string = original.string;
@@ -3021,11 +3120,7 @@
3021
3120
  clone.isVisible = original.isVisible;
3022
3121
  clone.isLeftHandTapped = original.isLeftHandTapped;
3023
3122
  clone.isHammerPullOrigin = original.isHammerPullOrigin;
3024
- clone.hammerPullOriginNoteId = original.hammerPullOriginNoteId;
3025
- clone.hammerPullDestinationNoteId = original.hammerPullDestinationNoteId;
3026
3123
  clone.isSlurDestination = original.isSlurDestination;
3027
- clone.slurOriginNoteId = original.slurOriginNoteId;
3028
- clone.slurDestinationNoteId = original.slurDestinationNoteId;
3029
3124
  clone.harmonicType = original.harmonicType;
3030
3125
  clone.harmonicValue = original.harmonicValue;
3031
3126
  clone.isGhost = original.isGhost;
@@ -3036,8 +3131,6 @@
3036
3131
  clone.slideInType = original.slideInType;
3037
3132
  clone.slideOutType = original.slideOutType;
3038
3133
  clone.vibrato = original.vibrato;
3039
- clone.tieOriginNoteId = original.tieOriginNoteId;
3040
- clone.tieDestinationNoteId = original.tieDestinationNoteId;
3041
3134
  clone.isTieDestination = original.isTieDestination;
3042
3135
  clone.leftHandFinger = original.leftHandFinger;
3043
3136
  clone.rightHandFinger = original.rightHandFinger;
@@ -3098,9 +3191,11 @@
3098
3191
  clone.tupletNumerator = original.tupletNumerator;
3099
3192
  clone.isContinuedWhammy = original.isContinuedWhammy;
3100
3193
  clone.whammyBarType = original.whammyBarType;
3101
- clone.whammyBarPoints = [];
3102
- for (const i of original.whammyBarPoints) {
3103
- clone.addWhammyBarPoint(BendPointCloner.clone(i));
3194
+ if (original.whammyBarPoints) {
3195
+ clone.whammyBarPoints = [];
3196
+ for (const i of original.whammyBarPoints) {
3197
+ clone.addWhammyBarPoint(BendPointCloner.clone(i));
3198
+ }
3104
3199
  }
3105
3200
  clone.vibrato = original.vibrato;
3106
3201
  clone.chordId = original.chordId;
@@ -3178,6 +3273,7 @@
3178
3273
  * A beat is a single block within a bar. A beat is a combination
3179
3274
  * of several notes played at the same time.
3180
3275
  * @json
3276
+ * @json_strict
3181
3277
  * @cloneable
3182
3278
  */
3183
3279
  class Beat {
@@ -3352,7 +3448,7 @@
3352
3448
  * @json_add addWhammyBarPoint
3353
3449
  * @clone_add addWhammyBarPoint
3354
3450
  */
3355
- this.whammyBarPoints = [];
3451
+ this.whammyBarPoints = null;
3356
3452
  /**
3357
3453
  * Gets or sets the highest point with for the highest whammy bar value.
3358
3454
  * @json_ignore
@@ -3473,13 +3569,13 @@
3473
3569
  !(this.tupletDenominator === 1 && this.tupletNumerator === 1));
3474
3570
  }
3475
3571
  get hasWhammyBar() {
3476
- return this.whammyBarType !== WhammyType.None;
3572
+ return this.whammyBarPoints !== null && this.whammyBarType !== WhammyType.None;
3477
3573
  }
3478
3574
  get hasChord() {
3479
3575
  return !!this.chordId;
3480
3576
  }
3481
3577
  get chord() {
3482
- return this.chordId ? this.voice.bar.staff.chords.get(this.chordId) : null;
3578
+ return this.chordId ? this.voice.bar.staff.getChord(this.chordId) : null;
3483
3579
  }
3484
3580
  get isTremolo() {
3485
3581
  return !!this.tremoloSpeed;
@@ -3494,7 +3590,12 @@
3494
3590
  return !!this.effectSlurOrigin;
3495
3591
  }
3496
3592
  addWhammyBarPoint(point) {
3497
- this.whammyBarPoints.push(point);
3593
+ let points = this.whammyBarPoints;
3594
+ if (points === null) {
3595
+ points = [];
3596
+ this.whammyBarPoints = points;
3597
+ }
3598
+ points.push(point);
3498
3599
  if (!this.maxWhammyPoint || point.value > this.maxWhammyPoint.value) {
3499
3600
  this.maxWhammyPoint = point;
3500
3601
  }
@@ -3507,16 +3608,17 @@
3507
3608
  }
3508
3609
  removeWhammyBarPoint(index) {
3509
3610
  // check index
3510
- if (index < 0 || index >= this.whammyBarPoints.length) {
3611
+ const points = this.whammyBarPoints;
3612
+ if (points === null || index < 0 || index >= points.length) {
3511
3613
  return;
3512
3614
  }
3513
3615
  // remove point
3514
- this.whammyBarPoints.splice(index, 1);
3515
- let point = this.whammyBarPoints[index];
3616
+ points.splice(index, 1);
3617
+ let point = points[index];
3516
3618
  // update maxWhammy point if required
3517
3619
  if (point === this.maxWhammyPoint) {
3518
3620
  this.maxWhammyPoint = null;
3519
- for (let currentPoint of this.whammyBarPoints) {
3621
+ for (let currentPoint of points) {
3520
3622
  if (!this.maxWhammyPoint || currentPoint.value > this.maxWhammyPoint.value) {
3521
3623
  this.maxWhammyPoint = currentPoint;
3522
3624
  }
@@ -3524,7 +3626,7 @@
3524
3626
  }
3525
3627
  if (point === this.minWhammyPoint) {
3526
3628
  this.minWhammyPoint = null;
3527
- for (let currentPoint of this.whammyBarPoints) {
3629
+ for (let currentPoint of points) {
3528
3630
  if (!this.minWhammyPoint || currentPoint.value < this.minWhammyPoint.value) {
3529
3631
  this.minWhammyPoint = currentPoint;
3530
3632
  }
@@ -3619,7 +3721,7 @@
3619
3721
  this.tupletGroup = currentTupletGroup;
3620
3722
  }
3621
3723
  }
3622
- finish(settings) {
3724
+ finish(settings, sharedDataBag) {
3623
3725
  if (this.getAutomation(AutomationType.Instrument) === null &&
3624
3726
  this.index === 0 &&
3625
3727
  this.voice.index === 0 &&
@@ -3658,7 +3760,7 @@
3658
3760
  for (let i = 0, j = this.notes.length; i < j; i++) {
3659
3761
  let note = this.notes[i];
3660
3762
  note.dynamics = this.dynamics;
3661
- note.finish(settings);
3763
+ note.finish(settings, sharedDataBag);
3662
3764
  if (note.isLetRing) {
3663
3765
  this.isLetRing = true;
3664
3766
  }
@@ -3749,17 +3851,18 @@
3749
3851
  }
3750
3852
  // try to detect what kind of bend was used and cleans unneeded points if required
3751
3853
  // Guitar Pro 6 and above (gpif.xml) uses exactly 4 points to define all whammys
3752
- if (this.whammyBarPoints.length > 0 && this.whammyBarType === WhammyType.Custom) {
3854
+ const points = this.whammyBarPoints;
3855
+ if (points !== null && points.length > 0 && this.whammyBarType === WhammyType.Custom) {
3753
3856
  if (displayMode === exports.NotationMode.SongBook) {
3754
3857
  this.whammyStyle = isGradual ? BendStyle.Gradual : BendStyle.Fast;
3755
3858
  }
3756
3859
  let isContinuedWhammy = !!this.previousBeat && this.previousBeat.hasWhammyBar;
3757
3860
  this.isContinuedWhammy = isContinuedWhammy;
3758
- if (this.whammyBarPoints.length === 4) {
3759
- let origin = this.whammyBarPoints[0];
3760
- let middle1 = this.whammyBarPoints[1];
3761
- let middle2 = this.whammyBarPoints[2];
3762
- let destination = this.whammyBarPoints[3];
3861
+ if (points.length === 4) {
3862
+ let origin = points[0];
3863
+ let middle1 = points[1];
3864
+ let middle2 = points[2];
3865
+ let destination = points[3];
3763
3866
  // the middle points are used for holds, anything else is a new feature we do not support yet
3764
3867
  if (middle1.value === middle2.value) {
3765
3868
  // constant decrease or increase
@@ -3771,14 +3874,14 @@
3771
3874
  else {
3772
3875
  this.whammyBarType = WhammyType.Dive;
3773
3876
  }
3774
- this.whammyBarPoints.splice(2, 1);
3775
- this.whammyBarPoints.splice(1, 1);
3877
+ points.splice(2, 1);
3878
+ points.splice(1, 1);
3776
3879
  }
3777
3880
  else if ((origin.value > middle1.value && middle1.value < destination.value) ||
3778
3881
  (origin.value < middle1.value && middle1.value > destination.value)) {
3779
3882
  this.whammyBarType = WhammyType.Dip;
3780
3883
  if (middle1.offset === middle2.offset || displayMode === exports.NotationMode.SongBook) {
3781
- this.whammyBarPoints.splice(2, 1);
3884
+ points.splice(2, 1);
3782
3885
  }
3783
3886
  }
3784
3887
  else if (origin.value === middle1.value && middle1.value === destination.value) {
@@ -3788,8 +3891,8 @@
3788
3891
  else {
3789
3892
  this.whammyBarType = WhammyType.Hold;
3790
3893
  }
3791
- this.whammyBarPoints.splice(2, 1);
3792
- this.whammyBarPoints.splice(1, 1);
3894
+ points.splice(2, 1);
3895
+ points.splice(1, 1);
3793
3896
  }
3794
3897
  else {
3795
3898
  Logger.warning('Model', 'Unsupported whammy type detected, fallback to custom', null);
@@ -3813,17 +3916,17 @@
3813
3916
  // remove bend on cloned note
3814
3917
  cloneNote.bendType = BendType.None;
3815
3918
  cloneNote.maxBendPoint = null;
3816
- cloneNote.bendPoints = [];
3919
+ cloneNote.bendPoints = null;
3817
3920
  cloneNote.bendStyle = BendStyle.Default;
3818
3921
  cloneNote.id = Note.GlobalNoteId++;
3819
3922
  // fix ties
3820
3923
  if (note.isTieOrigin) {
3821
- cloneNote.tieDestinationNoteId = note.tieDestination.id;
3822
- note.tieDestination.tieOriginNoteId = cloneNote.id;
3924
+ cloneNote.tieDestination = note.tieDestination;
3925
+ note.tieDestination.tieOrigin = cloneNote;
3823
3926
  }
3824
3927
  if (note.isTieDestination) {
3825
- cloneNote.tieOriginNoteId = note.tieOrigin ? note.tieOrigin.id : -1;
3826
- note.tieOrigin.tieDestinationNoteId = cloneNote.id;
3928
+ cloneNote.tieOrigin = note.tieOrigin ? note.tieOrigin : null;
3929
+ note.tieOrigin.tieDestination = cloneNote;
3827
3930
  }
3828
3931
  // if the note has a bend which is continued on the next note
3829
3932
  // we need to convert this note into a hold bend
@@ -3876,16 +3979,17 @@
3876
3979
  hasNoteOnString(noteString) {
3877
3980
  return this.noteStringLookup.has(noteString);
3878
3981
  }
3982
+ // TODO: can be likely eliminated
3879
3983
  getNoteWithRealValue(noteRealValue) {
3880
3984
  if (this.noteValueLookup.has(noteRealValue)) {
3881
3985
  return this.noteValueLookup.get(noteRealValue);
3882
3986
  }
3883
3987
  return null;
3884
3988
  }
3885
- chain() {
3989
+ chain(sharedDataBag) {
3886
3990
  for (const n of this.notes) {
3887
3991
  this.noteValueLookup.set(n.realValue, n);
3888
- n.chain();
3992
+ n.chain(sharedDataBag);
3889
3993
  }
3890
3994
  }
3891
3995
  }
@@ -3896,6 +4000,7 @@
3896
4000
  /**
3897
4001
  * A chord definition.
3898
4002
  * @json
4003
+ * @json_strict
3899
4004
  */
3900
4005
  class Chord {
3901
4006
  constructor() {
@@ -4188,6 +4293,7 @@
4188
4293
  * The MasterBar stores information about a bar which affects
4189
4294
  * all tracks.
4190
4295
  * @json
4296
+ * @json_strict
4191
4297
  */
4192
4298
  class MasterBar {
4193
4299
  constructor() {
@@ -4257,8 +4363,9 @@
4257
4363
  this.tempoAutomation = null;
4258
4364
  /**
4259
4365
  * Gets or sets the fermatas for this bar. The key is the offset of the fermata in midi ticks.
4366
+ * @json_add addFermata
4260
4367
  */
4261
- this.fermata = new Map();
4368
+ this.fermata = null;
4262
4369
  /**
4263
4370
  * The timeline position of the voice within the whole score. (unit: midi ticks)
4264
4371
  */
@@ -4300,7 +4407,12 @@
4300
4407
  * @param fermata The fermata.
4301
4408
  */
4302
4409
  addFermata(offset, fermata) {
4303
- this.fermata.set(offset, fermata);
4410
+ let fermataMap = this.fermata;
4411
+ if (fermataMap === null) {
4412
+ fermataMap = new Map();
4413
+ this.fermata = fermataMap;
4414
+ }
4415
+ fermataMap.set(offset, fermata);
4304
4416
  }
4305
4417
  /**
4306
4418
  * Gets the fermata for a given beat.
@@ -4308,8 +4420,12 @@
4308
4420
  * @returns
4309
4421
  */
4310
4422
  getFermata(beat) {
4311
- if (this.fermata.has(beat.playbackStart)) {
4312
- return this.fermata.get(beat.playbackStart);
4423
+ const fermataMap = this.fermata;
4424
+ if (fermataMap === null) {
4425
+ return null;
4426
+ }
4427
+ if (fermataMap.has(beat.playbackStart)) {
4428
+ return fermataMap.get(beat.playbackStart);
4313
4429
  }
4314
4430
  return null;
4315
4431
  }
@@ -4320,6 +4436,7 @@
4320
4436
  * This class represents the rendering stylesheet.
4321
4437
  * It contains settings which control the display of the score when rendered.
4322
4438
  * @json
4439
+ * @json_strict
4323
4440
  */
4324
4441
  class RenderStylesheet {
4325
4442
  constructor() {
@@ -4382,10 +4499,10 @@
4382
4499
  * model. It stores the basic information of
4383
4500
  * a song and stores the sub components.
4384
4501
  * @json
4502
+ * @json_strict
4385
4503
  */
4386
4504
  class Score {
4387
4505
  constructor() {
4388
- this._noteByIdLookup = new Map();
4389
4506
  this._currentRepeatGroup = new RepeatGroup();
4390
4507
  /**
4391
4508
  * The album of this song.
@@ -4468,7 +4585,12 @@
4468
4585
  if (this.masterBars.length !== 0) {
4469
4586
  bar.previousMasterBar = this.masterBars[this.masterBars.length - 1];
4470
4587
  bar.previousMasterBar.nextMasterBar = bar;
4471
- bar.start = bar.previousMasterBar.start + bar.previousMasterBar.calculateDuration();
4588
+ // TODO: this will not work on anacrusis. Correct anacrusis durations are only working
4589
+ // when there are beats with playback positions already computed which requires full finish
4590
+ // chicken-egg problem here. temporarily forcing anacrusis length here to 0
4591
+ bar.start =
4592
+ bar.previousMasterBar.start +
4593
+ (bar.previousMasterBar.isAnacrusis ? 0 : bar.previousMasterBar.calculateDuration());
4472
4594
  }
4473
4595
  // if the group is closed only the next upcoming header can
4474
4596
  // reopen the group in case of a repeat alternative, so we
@@ -4485,25 +4607,18 @@
4485
4607
  this.tracks.push(track);
4486
4608
  }
4487
4609
  finish(settings) {
4488
- this._noteByIdLookup.clear();
4610
+ const sharedDataBag = new Map();
4489
4611
  for (let i = 0, j = this.tracks.length; i < j; i++) {
4490
- this.tracks[i].finish(settings);
4612
+ this.tracks[i].finish(settings, sharedDataBag);
4491
4613
  }
4492
4614
  }
4493
- registerNote(note) {
4494
- this._noteByIdLookup.set(note.id, note);
4495
- }
4496
- getNoteById(noteId) {
4497
- return this._noteByIdLookup.has(noteId)
4498
- ? this._noteByIdLookup.get(noteId)
4499
- : null;
4500
- }
4501
4615
  }
4502
4616
 
4503
4617
  /**
4504
4618
  * This public class is used to describe the beginning of a
4505
4619
  * section within a song. It acts like a marker.
4506
4620
  * @json
4621
+ * @json_strict
4507
4622
  */
4508
4623
  class Section {
4509
4624
  constructor() {
@@ -4576,50 +4691,48 @@
4576
4691
  }
4577
4692
  static fromJson(v) {
4578
4693
  switch (typeof v) {
4579
- case 'number':
4580
- {
4581
- const c = new Color(0, 0, 0, 0);
4582
- c.raw = v;
4583
- c.updateRgba();
4584
- return c;
4694
+ case 'number': {
4695
+ const c = new Color(0, 0, 0, 0);
4696
+ c.raw = v;
4697
+ c.updateRgba();
4698
+ return c;
4699
+ }
4700
+ case 'string': {
4701
+ const json = v;
4702
+ if (json.startsWith('#')) {
4703
+ if (json.length === 4) {
4704
+ // #RGB
4705
+ return new Color(parseInt(json.substring(1, 1), 16) * 17, parseInt(json.substring(2, 1), 16) * 17, parseInt(json.substring(3, 1), 16) * 17);
4706
+ }
4707
+ if (json.length === 5) {
4708
+ // #RGBA
4709
+ return new Color(parseInt(json.substring(1, 1), 16) * 17, parseInt(json.substring(2, 1), 16) * 17, parseInt(json.substring(3, 1), 16) * 17, parseInt(json.substring(4, 1), 16) * 17);
4710
+ }
4711
+ if (json.length === 7) {
4712
+ // #RRGGBB
4713
+ return new Color(parseInt(json.substring(1, 2), 16), parseInt(json.substring(3, 2), 16), parseInt(json.substring(5, 2), 16));
4714
+ }
4715
+ if (json.length === 9) {
4716
+ // #RRGGBBAA
4717
+ return new Color(parseInt(json.substring(1, 2), 16), parseInt(json.substring(3, 2), 16), parseInt(json.substring(5, 2), 16), parseInt(json.substring(7, 2), 16));
4718
+ }
4585
4719
  }
4586
- case 'string':
4587
- {
4588
- const json = v;
4589
- if (json.startsWith('#')) {
4590
- if (json.length === 4) {
4591
- // #RGB
4592
- return new Color(parseInt(json.substring(1, 1), 16) * 17, parseInt(json.substring(2, 1), 16) * 17, parseInt(json.substring(3, 1), 16) * 17);
4593
- }
4594
- if (json.length === 5) {
4595
- // #RGBA
4596
- return new Color(parseInt(json.substring(1, 1), 16) * 17, parseInt(json.substring(2, 1), 16) * 17, parseInt(json.substring(3, 1), 16) * 17, parseInt(json.substring(4, 1), 16) * 17);
4597
- }
4598
- if (json.length === 7) {
4599
- // #RRGGBB
4600
- return new Color(parseInt(json.substring(1, 2), 16), parseInt(json.substring(3, 2), 16), parseInt(json.substring(5, 2), 16));
4601
- }
4602
- if (json.length === 9) {
4603
- // #RRGGBBAA
4604
- return new Color(parseInt(json.substring(1, 2), 16), parseInt(json.substring(3, 2), 16), parseInt(json.substring(5, 2), 16), parseInt(json.substring(7, 2), 16));
4605
- }
4720
+ else if (json.startsWith('rgba') || json.startsWith('rgb')) {
4721
+ const start = json.indexOf('(');
4722
+ const end = json.lastIndexOf(')');
4723
+ if (start === -1 || end === -1) {
4724
+ throw new FormatError('No values specified for rgb/rgba function');
4606
4725
  }
4607
- else if (json.startsWith('rgba') || json.startsWith('rgb')) {
4608
- const start = json.indexOf('(');
4609
- const end = json.lastIndexOf(')');
4610
- if (start === -1 || end === -1) {
4611
- throw new FormatError('No values specified for rgb/rgba function');
4612
- }
4613
- const numbers = json.substring(start + 1, end).split(',');
4614
- if (numbers.length === 3) {
4615
- return new Color(parseInt(numbers[0]), parseInt(numbers[1]), parseInt(numbers[2]));
4616
- }
4617
- if (numbers.length === 4) {
4618
- return new Color(parseInt(numbers[0]), parseInt(numbers[1]), parseInt(numbers[2]), parseFloat(numbers[3]) * 255);
4619
- }
4726
+ const numbers = json.substring(start + 1, end).split(',');
4727
+ if (numbers.length === 3) {
4728
+ return new Color(parseInt(numbers[0]), parseInt(numbers[1]), parseInt(numbers[2]));
4729
+ }
4730
+ if (numbers.length === 4) {
4731
+ return new Color(parseInt(numbers[0]), parseInt(numbers[1]), parseInt(numbers[2]), parseFloat(numbers[3]) * 255);
4620
4732
  }
4621
- return null;
4622
4733
  }
4734
+ return null;
4735
+ }
4623
4736
  }
4624
4737
  throw new FormatError('Unsupported format for color');
4625
4738
  }
@@ -4633,6 +4746,7 @@
4633
4746
  * This public class stores the midi specific information of a track needed
4634
4747
  * for playback.
4635
4748
  * @json
4749
+ * @json_strict
4636
4750
  */
4637
4751
  class PlaybackInformation {
4638
4752
  constructor() {
@@ -4674,6 +4788,7 @@
4674
4788
  /**
4675
4789
  * This public class represents a predefined string tuning.
4676
4790
  * @json
4791
+ * @json_strict
4677
4792
  */
4678
4793
  class Tuning {
4679
4794
  /**
@@ -4829,6 +4944,7 @@
4829
4944
  * This class describes a single staff within a track. There are instruments like pianos
4830
4945
  * where a single track can contain multiple staffs.
4831
4946
  * @json
4947
+ * @json_strict
4832
4948
  */
4833
4949
  class Staff {
4834
4950
  constructor() {
@@ -4846,7 +4962,7 @@
4846
4962
  * Gets or sets a list of all chords defined for this staff. {@link Beat.chordId} refers to entries in this lookup.
4847
4963
  * @json_add addChord
4848
4964
  */
4849
- this.chords = new Map();
4965
+ this.chords = null;
4850
4966
  /**
4851
4967
  * Gets or sets the fret on which a capo is set.
4852
4968
  */
@@ -4900,15 +5016,28 @@
4900
5016
  get isStringed() {
4901
5017
  return this.stringTuning.tunings.length > 0;
4902
5018
  }
4903
- finish(settings) {
5019
+ finish(settings, sharedDataBag) {
4904
5020
  this.stringTuning.finish();
4905
5021
  for (let i = 0, j = this.bars.length; i < j; i++) {
4906
- this.bars[i].finish(settings);
5022
+ this.bars[i].finish(settings, sharedDataBag);
4907
5023
  }
4908
5024
  }
4909
5025
  addChord(chordId, chord) {
4910
5026
  chord.staff = this;
4911
- this.chords.set(chordId, chord);
5027
+ let chordMap = this.chords;
5028
+ if (chordMap === null) {
5029
+ chordMap = new Map();
5030
+ this.chords = chordMap;
5031
+ }
5032
+ chordMap.set(chordId, chord);
5033
+ }
5034
+ hasChord(chordId) {
5035
+ var _a, _b;
5036
+ return (_b = (_a = this.chords) === null || _a === void 0 ? void 0 : _a.has(chordId)) !== null && _b !== void 0 ? _b : false;
5037
+ }
5038
+ getChord(chordId) {
5039
+ var _a, _b;
5040
+ return (_b = (_a = this.chords) === null || _a === void 0 ? void 0 : _a.get(chordId)) !== null && _b !== void 0 ? _b : null;
4912
5041
  }
4913
5042
  addBar(bar) {
4914
5043
  let bars = this.bars;
@@ -4926,6 +5055,7 @@
4926
5055
  * This public class describes a single track or instrument of score.
4927
5056
  * It is bascially a list of staffs containing individual music notation kinds.
4928
5057
  * @json
5058
+ * @json_strict
4929
5059
  */
4930
5060
  class Track {
4931
5061
  constructor() {
@@ -4971,7 +5101,7 @@
4971
5101
  staff.track = this;
4972
5102
  this.staves.push(staff);
4973
5103
  }
4974
- finish(settings) {
5104
+ finish(settings, sharedDataBag) {
4975
5105
  if (!this.shortName) {
4976
5106
  this.shortName = this.name;
4977
5107
  if (this.shortName.length > Track.ShortNameMaxLength) {
@@ -4979,7 +5109,7 @@
4979
5109
  }
4980
5110
  }
4981
5111
  for (let i = 0, j = this.staves.length; i < j; i++) {
4982
- this.staves[i].finish(settings);
5112
+ this.staves[i].finish(settings, sharedDataBag);
4983
5113
  }
4984
5114
  }
4985
5115
  applyLyrics(lyrics) {
@@ -5017,6 +5147,7 @@
5017
5147
  * A voice represents a group of beats
5018
5148
  * that can be played during a bar.
5019
5149
  * @json
5150
+ * @json_strict
5020
5151
  */
5021
5152
  class Voice$1 {
5022
5153
  constructor() {
@@ -5057,7 +5188,7 @@
5057
5188
  this.isEmpty = false;
5058
5189
  }
5059
5190
  }
5060
- chain(beat) {
5191
+ chain(beat, sharedDataBag) {
5061
5192
  if (!this.bar) {
5062
5193
  return;
5063
5194
  }
@@ -5075,7 +5206,7 @@
5075
5206
  beat.nextBeat.previousBeat = beat;
5076
5207
  }
5077
5208
  }
5078
- beat.chain();
5209
+ beat.chain(sharedDataBag);
5079
5210
  }
5080
5211
  addGraceBeat(beat) {
5081
5212
  if (this.beats.length === 0) {
@@ -5097,13 +5228,13 @@
5097
5228
  }
5098
5229
  return null;
5099
5230
  }
5100
- finish(settings) {
5231
+ finish(settings, sharedDataBag) {
5101
5232
  this._beatLookup = new Map();
5102
5233
  let currentGraceGroup = null;
5103
5234
  for (let index = 0; index < this.beats.length; index++) {
5104
5235
  let beat = this.beats[index];
5105
5236
  beat.index = index;
5106
- this.chain(beat);
5237
+ this.chain(beat, sharedDataBag);
5107
5238
  if (beat.graceType === GraceType.None) {
5108
5239
  beat.graceGroup = currentGraceGroup;
5109
5240
  if (currentGraceGroup) {
@@ -5123,7 +5254,7 @@
5123
5254
  for (let i = 0; i < this.beats.length; i++) {
5124
5255
  let beat = this.beats[i];
5125
5256
  beat.index = i;
5126
- beat.finish(settings);
5257
+ beat.finish(settings, sharedDataBag);
5127
5258
  // if this beat is a non-grace but has grace notes
5128
5259
  // we need to first steal the duration from the right beat
5129
5260
  // and place the grace beats correctly
@@ -5209,7 +5340,18 @@
5209
5340
  }
5210
5341
  Voice$1._globalBarId = 0;
5211
5342
 
5343
+ /**
5344
+ * @target web
5345
+ */
5212
5346
  class TypeConversions {
5347
+ static float64ToBytes(v) {
5348
+ TypeConversions._dataView.setFloat64(0, v, true);
5349
+ return this._conversionByteArray;
5350
+ }
5351
+ static bytesToFloat64(bytes) {
5352
+ TypeConversions._conversionByteArray.set(bytes, 0);
5353
+ throw TypeConversions._dataView.getFloat64(0, true);
5354
+ }
5213
5355
  static uint16ToInt16(v) {
5214
5356
  TypeConversions._dataView.setUint16(0, v, true);
5215
5357
  return TypeConversions._dataView.getInt16(0, true);
@@ -5236,6 +5378,7 @@
5236
5378
  }
5237
5379
  }
5238
5380
  TypeConversions._conversionBuffer = new ArrayBuffer(8);
5381
+ TypeConversions._conversionByteArray = new Uint8Array(TypeConversions._conversionBuffer);
5239
5382
  TypeConversions._dataView = new DataView(TypeConversions._conversionBuffer);
5240
5383
 
5241
5384
  class IOHelper {
@@ -5374,30 +5517,29 @@
5374
5517
  return decoder.encode(str);
5375
5518
  }
5376
5519
  static writeInt32BE(o, v) {
5377
- o.writeByte((v >> 24) & 0xFF);
5378
- o.writeByte((v >> 16) & 0xFF);
5379
- o.writeByte((v >> 8) & 0xFF);
5380
- o.writeByte((v >> 0) & 0xFF);
5520
+ o.writeByte((v >> 24) & 0xff);
5521
+ o.writeByte((v >> 16) & 0xff);
5522
+ o.writeByte((v >> 8) & 0xff);
5523
+ o.writeByte((v >> 0) & 0xff);
5381
5524
  }
5382
5525
  static writeInt32LE(o, v) {
5383
- o.writeByte((v >> 0) & 0xFF);
5384
- o.writeByte((v >> 8) & 0xFF);
5385
- o.writeByte((v >> 16) & 0xFF);
5386
- o.writeByte((v >> 24) & 0xFF);
5526
+ o.writeByte((v >> 0) & 0xff);
5527
+ o.writeByte((v >> 8) & 0xff);
5528
+ o.writeByte((v >> 16) & 0xff);
5529
+ o.writeByte((v >> 24) & 0xff);
5387
5530
  }
5388
5531
  static writeUInt16LE(o, v) {
5389
- o.writeByte((v >> 0) & 0xFF);
5390
- o.writeByte((v >> 8) & 0xFF);
5532
+ o.writeByte((v >> 0) & 0xff);
5533
+ o.writeByte((v >> 8) & 0xff);
5391
5534
  }
5392
5535
  static writeInt16LE(o, v) {
5393
- o.writeByte((v >> 0) & 0xFF);
5394
- o.writeByte((v >> 8) & 0xFF);
5536
+ o.writeByte((v >> 0) & 0xff);
5537
+ o.writeByte((v >> 8) & 0xff);
5395
5538
  }
5396
5539
  }
5397
5540
 
5398
5541
  class ByteBuffer {
5399
5542
  constructor() {
5400
- this._capacity = 0;
5401
5543
  this.length = 0;
5402
5544
  this.position = 0;
5403
5545
  }
@@ -5413,14 +5555,12 @@
5413
5555
  static withCapacity(capacity) {
5414
5556
  let buffer = new ByteBuffer();
5415
5557
  buffer._buffer = new Uint8Array(capacity);
5416
- buffer._capacity = capacity;
5417
5558
  return buffer;
5418
5559
  }
5419
5560
  static fromBuffer(data) {
5420
5561
  let buffer = new ByteBuffer();
5421
5562
  buffer._buffer = data;
5422
5563
  buffer.length = data.length;
5423
- buffer._capacity = buffer.length;
5424
5564
  return buffer;
5425
5565
  }
5426
5566
  static fromString(contents) {
@@ -5433,18 +5573,6 @@
5433
5573
  skip(offset) {
5434
5574
  this.position += offset;
5435
5575
  }
5436
- setCapacity(value) {
5437
- if (value !== this._capacity) {
5438
- if (value > 0) {
5439
- let newBuffer = new Uint8Array(value);
5440
- if (this.length > 0) {
5441
- newBuffer.set(this._buffer.subarray(0, 0 + this.length), 0);
5442
- }
5443
- this._buffer = newBuffer;
5444
- }
5445
- this._capacity = value;
5446
- }
5447
- }
5448
5576
  readByte() {
5449
5577
  let n = this.length - this.position;
5450
5578
  if (n <= 0) {
@@ -5460,53 +5588,43 @@
5460
5588
  if (n <= 0) {
5461
5589
  return 0;
5462
5590
  }
5463
- if (n <= 8) {
5464
- let byteCount = n;
5465
- while (--byteCount >= 0) {
5466
- buffer[offset + byteCount] = this._buffer[this.position + byteCount];
5467
- }
5468
- }
5469
- else {
5470
- buffer.set(this._buffer.subarray(this.position, this.position + n), offset);
5471
- }
5591
+ buffer.set(this._buffer.subarray(this.position, this.position + n), offset);
5472
5592
  this.position += n;
5473
5593
  return n;
5474
5594
  }
5475
5595
  writeByte(value) {
5476
- let buffer = new Uint8Array(1);
5477
- buffer[0] = value;
5478
- this.write(buffer, 0, 1);
5596
+ let i = this.position + 1;
5597
+ this.ensureCapacity(i);
5598
+ this._buffer[this.position] = value & 0xFF;
5599
+ if (i > this.length) {
5600
+ this.length = i;
5601
+ }
5602
+ this.position = i;
5479
5603
  }
5480
5604
  write(buffer, offset, count) {
5481
5605
  let i = this.position + count;
5606
+ this.ensureCapacity(i);
5607
+ let count1 = Math.min(count, buffer.length - offset);
5608
+ this._buffer.set(buffer.subarray(offset, offset + count1), this.position);
5482
5609
  if (i > this.length) {
5483
- if (i > this._capacity) {
5484
- this.ensureCapacity(i);
5485
- }
5486
5610
  this.length = i;
5487
5611
  }
5488
- if (count <= 8 && buffer !== this._buffer) {
5489
- let byteCount = count;
5490
- while (--byteCount >= 0) {
5491
- this._buffer[this.position + byteCount] = buffer[offset + byteCount];
5492
- }
5493
- }
5494
- else {
5495
- let count1 = Math.min(count, buffer.length - offset);
5496
- this._buffer.set(buffer.subarray(offset, offset + count1), this.position);
5497
- }
5498
5612
  this.position = i;
5499
5613
  }
5500
5614
  ensureCapacity(value) {
5501
- if (value > this._capacity) {
5615
+ if (value > this._buffer.length) {
5502
5616
  let newCapacity = value;
5503
5617
  if (newCapacity < 256) {
5504
5618
  newCapacity = 256;
5505
5619
  }
5506
- if (newCapacity < this._capacity * 2) {
5507
- newCapacity = this._capacity * 2;
5620
+ if (newCapacity < this._buffer.length * 2) {
5621
+ newCapacity = this._buffer.length * 2;
5622
+ }
5623
+ let newBuffer = new Uint8Array(newCapacity);
5624
+ if (this.length > 0) {
5625
+ newBuffer.set(this._buffer.subarray(0, 0 + this.length), 0);
5508
5626
  }
5509
- this.setCapacity(newCapacity);
5627
+ this._buffer = newBuffer;
5510
5628
  }
5511
5629
  }
5512
5630
  readAll() {
@@ -6167,6 +6285,7 @@
6167
6285
  return anyMeta;
6168
6286
  }
6169
6287
  handleStaffMeta() {
6288
+ var _a, _b;
6170
6289
  let syData = this._syData.toLowerCase();
6171
6290
  switch (syData) {
6172
6291
  case 'capo':
@@ -6210,7 +6329,7 @@
6210
6329
  this.error('tuning', AlphaTexSymbols.Tuning, true);
6211
6330
  break;
6212
6331
  }
6213
- if (strings !== this._currentStaff.tuning.length && this._currentStaff.chords.size > 0) {
6332
+ if (strings !== this._currentStaff.tuning.length && ((_b = (_a = this._currentStaff.chords) === null || _a === void 0 ? void 0 : _a.size) !== null && _b !== void 0 ? _b : 0) > 0) {
6214
6333
  this.errorMessage('Tuning must be defined before any chord');
6215
6334
  }
6216
6335
  return true;
@@ -6761,23 +6880,25 @@
6761
6880
  beat.addWhammyBarPoint(new BendPoint(offset, value));
6762
6881
  this._sy = this.newSy();
6763
6882
  }
6764
- while (beat.whammyBarPoints.length > 60) {
6765
- beat.removeWhammyBarPoint(beat.whammyBarPoints.length - 1);
6766
- }
6767
- // set positions
6768
- if (!exact) {
6769
- let count = beat.whammyBarPoints.length;
6770
- let step = (60 / count) | 0;
6771
- let i = 0;
6772
- while (i < count) {
6773
- beat.whammyBarPoints[i].offset = Math.min(60, i * step);
6774
- i++;
6883
+ if (beat.whammyBarPoints != null) {
6884
+ while (beat.whammyBarPoints.length > 60) {
6885
+ beat.removeWhammyBarPoint(beat.whammyBarPoints.length - 1);
6886
+ }
6887
+ // set positions
6888
+ if (!exact) {
6889
+ let count = beat.whammyBarPoints.length;
6890
+ let step = (60 / count) | 0;
6891
+ let i = 0;
6892
+ while (i < count) {
6893
+ beat.whammyBarPoints[i].offset = Math.min(60, i * step);
6894
+ i++;
6895
+ }
6896
+ }
6897
+ else {
6898
+ beat.whammyBarPoints.sort((a, b) => {
6899
+ return a.offset - b.offset;
6900
+ });
6775
6901
  }
6776
- }
6777
- else {
6778
- beat.whammyBarPoints.sort((a, b) => {
6779
- return a.offset - b.offset;
6780
- });
6781
6902
  }
6782
6903
  this._allowNegatives = false;
6783
6904
  if (this._sy !== AlphaTexSymbols.RParensis) {
@@ -6791,7 +6912,7 @@
6791
6912
  this._sy = this.newSy();
6792
6913
  let chordName = this._syData;
6793
6914
  let chordId = this.getChordId(this._currentStaff, chordName);
6794
- if (!this._currentStaff.chords.has(chordId)) {
6915
+ if (!this._currentStaff.hasChord(chordId)) {
6795
6916
  let chord = new Chord();
6796
6917
  chord.showDiagram = false;
6797
6918
  chord.name = chordName;
@@ -7034,22 +7155,25 @@
7034
7155
  note.addBendPoint(new BendPoint(offset, value));
7035
7156
  this._sy = this.newSy();
7036
7157
  }
7037
- while (note.bendPoints.length > 60) {
7038
- note.bendPoints.splice(note.bendPoints.length - 1, 1);
7039
- }
7040
- // set positions
7041
- if (exact) {
7042
- note.bendPoints.sort((a, b) => {
7043
- return a.offset - b.offset;
7044
- });
7045
- }
7046
- else {
7047
- let count = note.bendPoints.length;
7048
- let step = (60 / (count - 1)) | 0;
7049
- let i = 0;
7050
- while (i < count) {
7051
- note.bendPoints[i].offset = Math.min(60, i * step);
7052
- i++;
7158
+ const points = note.bendPoints;
7159
+ if (points != null) {
7160
+ while (points.length > 60) {
7161
+ points.splice(points.length - 1, 1);
7162
+ }
7163
+ // set positions
7164
+ if (exact) {
7165
+ points.sort((a, b) => {
7166
+ return a.offset - b.offset;
7167
+ });
7168
+ }
7169
+ else {
7170
+ let count = points.length;
7171
+ let step = (60 / (count - 1)) | 0;
7172
+ let i = 0;
7173
+ while (i < count) {
7174
+ points[i].offset = Math.min(60, i * step);
7175
+ i++;
7176
+ }
7053
7177
  }
7054
7178
  }
7055
7179
  if (this._sy !== AlphaTexSymbols.RParensis) {
@@ -8785,6 +8909,7 @@
8785
8909
  /**
8786
8910
  * Represents a fermata.
8787
8911
  * @json
8912
+ * @json_strict
8788
8913
  */
8789
8914
  class Fermata {
8790
8915
  constructor() {
@@ -12346,7 +12471,8 @@
12346
12471
  super(exports.AlphaTabErrorType.Format, 'Unexpected end of data within reader');
12347
12472
  Object.setPrototypeOf(this, EndOfReaderError.prototype);
12348
12473
  }
12349
- }
12474
+ }
12475
+
12350
12476
  /**
12351
12477
  * This utility public class allows bitwise reading of a stream
12352
12478
  */
@@ -13428,7 +13554,7 @@
13428
13554
  }
13429
13555
  else if (element.getAttribute('type') === 'stop' && this._tieStarts.length > 0 && !note.isTieDestination) {
13430
13556
  note.isTieDestination = true;
13431
- note.tieOriginNoteId = this._tieStarts[0].id;
13557
+ note.tieOrigin = this._tieStarts[0];
13432
13558
  this._tieStarts.splice(0, 1);
13433
13559
  this._tieStartIds.delete(note.id);
13434
13560
  }
@@ -13471,8 +13597,8 @@
13471
13597
  if (this._slurStarts.has(slurNumber)) {
13472
13598
  note.isSlurDestination = true;
13473
13599
  let slurStart = this._slurStarts.get(slurNumber);
13474
- slurStart.slurDestinationNoteId = note.id;
13475
- note.slurOriginNoteId = note.id;
13600
+ slurStart.slurDestination = note;
13601
+ note.slurOrigin = note;
13476
13602
  }
13477
13603
  break;
13478
13604
  }
@@ -14290,7 +14416,7 @@
14290
14416
  this.firstTimeSignatureNumerator = 0;
14291
14417
  this.firstTimeSignatureDenominator = 0;
14292
14418
  this.synthData = [];
14293
- this.division = 0;
14419
+ this.division = MidiUtils.QuarterTime;
14294
14420
  this.eventIndex = 0;
14295
14421
  this.currentTime = 0;
14296
14422
  this.playbackRange = null;
@@ -14800,13 +14926,12 @@
14800
14926
  const samples = new Float32Array(samplesLeft);
14801
14927
  let samplesPos = 0;
14802
14928
  const sampleBuffer = new Uint8Array(2048);
14803
- const testBuffer = new Int16Array((sampleBuffer.length / 2) | 0);
14804
14929
  while (samplesLeft > 0) {
14805
14930
  let samplesToRead = Math.min(samplesLeft, (sampleBuffer.length / 2) | 0);
14806
14931
  reader.read(sampleBuffer, 0, samplesToRead * 2);
14807
14932
  for (let i = 0; i < samplesToRead; i++) {
14808
- testBuffer[i] = (sampleBuffer[i * 2 + 1] << 8) | sampleBuffer[i * 2];
14809
- samples[samplesPos + i] = testBuffer[i] / 32767;
14933
+ const shortSample = TypeConversions.int32ToInt16((sampleBuffer[i * 2 + 1] << 8) | sampleBuffer[i * 2]);
14934
+ samples[samplesPos + i] = shortSample / 32767;
14810
14935
  }
14811
14936
  samplesLeft -= samplesToRead;
14812
14937
  samplesPos += samplesToRead;
@@ -17828,8 +17953,7 @@
17828
17953
  }
17829
17954
  else if (parts.length >= 1) {
17830
17955
  this.size = parts[0];
17831
- if (this._currentToken &&
17832
- this._currentToken.text.indexOf('/') === 0) {
17956
+ if (this._currentToken && this._currentToken.text.indexOf('/') === 0) {
17833
17957
  // size / line-height (with spaces befor and after slash)
17834
17958
  if (this._currentToken.text === '/') {
17835
17959
  this.nextToken();
@@ -18495,20 +18619,20 @@
18495
18619
  }
18496
18620
  const o = new Map();
18497
18621
  /*@target web*/
18498
- o.set("scriptFile", obj.scriptFile);
18622
+ o.set("scriptfile", obj.scriptFile);
18499
18623
  /*@target web*/
18500
- o.set("fontDirectory", obj.fontDirectory);
18624
+ o.set("fontdirectory", obj.fontDirectory);
18501
18625
  /*@target web*/
18502
18626
  o.set("file", obj.file);
18503
18627
  /*@target web*/
18504
18628
  o.set("tex", obj.tex);
18505
18629
  /*@target web*/
18506
18630
  o.set("tracks", obj.tracks);
18507
- o.set("enableLazyLoading", obj.enableLazyLoading);
18631
+ o.set("enablelazyloading", obj.enableLazyLoading);
18508
18632
  o.set("engine", obj.engine);
18509
- o.set("logLevel", obj.logLevel);
18510
- o.set("useWorkers", obj.useWorkers);
18511
- o.set("includeNoteBounds", obj.includeNoteBounds);
18633
+ o.set("loglevel", obj.logLevel);
18634
+ o.set("useworkers", obj.useWorkers);
18635
+ o.set("includenotebounds", obj.includeNoteBounds);
18512
18636
  return o;
18513
18637
  }
18514
18638
  static setProperty(obj, property, v) {
@@ -18565,23 +18689,23 @@
18565
18689
  return null;
18566
18690
  }
18567
18691
  const o = new Map();
18568
- o.set("copyrightFont", Font.toJson(obj.copyrightFont));
18569
- o.set("titleFont", Font.toJson(obj.titleFont));
18570
- o.set("subTitleFont", Font.toJson(obj.subTitleFont));
18571
- o.set("wordsFont", Font.toJson(obj.wordsFont));
18572
- o.set("effectFont", Font.toJson(obj.effectFont));
18573
- o.set("fretboardNumberFont", Font.toJson(obj.fretboardNumberFont));
18574
- o.set("tablatureFont", Font.toJson(obj.tablatureFont));
18575
- o.set("graceFont", Font.toJson(obj.graceFont));
18576
- o.set("staffLineColor", Color.toJson(obj.staffLineColor));
18577
- o.set("barSeparatorColor", Color.toJson(obj.barSeparatorColor));
18578
- o.set("barNumberFont", Font.toJson(obj.barNumberFont));
18579
- o.set("barNumberColor", Color.toJson(obj.barNumberColor));
18580
- o.set("fingeringFont", Font.toJson(obj.fingeringFont));
18581
- o.set("markerFont", Font.toJson(obj.markerFont));
18582
- o.set("mainGlyphColor", Color.toJson(obj.mainGlyphColor));
18583
- o.set("secondaryGlyphColor", Color.toJson(obj.secondaryGlyphColor));
18584
- o.set("scoreInfoColor", Color.toJson(obj.scoreInfoColor));
18692
+ o.set("copyrightfont", Font.toJson(obj.copyrightFont));
18693
+ o.set("titlefont", Font.toJson(obj.titleFont));
18694
+ o.set("subtitlefont", Font.toJson(obj.subTitleFont));
18695
+ o.set("wordsfont", Font.toJson(obj.wordsFont));
18696
+ o.set("effectfont", Font.toJson(obj.effectFont));
18697
+ o.set("fretboardnumberfont", Font.toJson(obj.fretboardNumberFont));
18698
+ o.set("tablaturefont", Font.toJson(obj.tablatureFont));
18699
+ o.set("gracefont", Font.toJson(obj.graceFont));
18700
+ o.set("stafflinecolor", Color.toJson(obj.staffLineColor));
18701
+ o.set("barseparatorcolor", Color.toJson(obj.barSeparatorColor));
18702
+ o.set("barnumberfont", Font.toJson(obj.barNumberFont));
18703
+ o.set("barnumbercolor", Color.toJson(obj.barNumberColor));
18704
+ o.set("fingeringfont", Font.toJson(obj.fingeringFont));
18705
+ o.set("markerfont", Font.toJson(obj.markerFont));
18706
+ o.set("mainglyphcolor", Color.toJson(obj.mainGlyphColor));
18707
+ o.set("secondaryglyphcolor", Color.toJson(obj.secondaryGlyphColor));
18708
+ o.set("scoreinfocolor", Color.toJson(obj.scoreInfoColor));
18585
18709
  return o;
18586
18710
  }
18587
18711
  static setProperty(obj, property, v) {
@@ -18655,13 +18779,13 @@
18655
18779
  }
18656
18780
  const o = new Map();
18657
18781
  o.set("scale", obj.scale);
18658
- o.set("stretchForce", obj.stretchForce);
18659
- o.set("layoutMode", obj.layoutMode);
18660
- o.set("staveProfile", obj.staveProfile);
18661
- o.set("barsPerRow", obj.barsPerRow);
18662
- o.set("startBar", obj.startBar);
18663
- o.set("barCount", obj.barCount);
18664
- o.set("barCountPerPartial", obj.barCountPerPartial);
18782
+ o.set("stretchforce", obj.stretchForce);
18783
+ o.set("layoutmode", obj.layoutMode);
18784
+ o.set("staveprofile", obj.staveProfile);
18785
+ o.set("barsperrow", obj.barsPerRow);
18786
+ o.set("startbar", obj.startBar);
18787
+ o.set("barcount", obj.barCount);
18788
+ o.set("barcountperpartial", obj.barCountPerPartial);
18665
18789
  o.set("resources", RenderingResourcesSerializer.toJson(obj.resources));
18666
18790
  o.set("padding", obj.padding);
18667
18791
  return o;
@@ -18725,8 +18849,8 @@
18725
18849
  return null;
18726
18850
  }
18727
18851
  const o = new Map();
18728
- o.set("notationMode", obj.notationMode);
18729
- o.set("fingeringMode", obj.fingeringMode);
18852
+ o.set("notationmode", obj.notationMode);
18853
+ o.set("fingeringmode", obj.fingeringMode);
18730
18854
  {
18731
18855
  const m = new Map();
18732
18856
  o.set("elements", m);
@@ -18734,14 +18858,14 @@
18734
18858
  m.set(k.toString(), v);
18735
18859
  }
18736
18860
  }
18737
- o.set("rhythmMode", obj.rhythmMode);
18738
- o.set("rhythmHeight", obj.rhythmHeight);
18739
- o.set("transpositionPitches", obj.transpositionPitches);
18740
- o.set("displayTranspositionPitches", obj.displayTranspositionPitches);
18741
- o.set("smallGraceTabNotes", obj.smallGraceTabNotes);
18742
- o.set("extendBendArrowsOnTiedNotes", obj.extendBendArrowsOnTiedNotes);
18743
- o.set("extendLineEffectsToBeatEnd", obj.extendLineEffectsToBeatEnd);
18744
- o.set("slurHeight", obj.slurHeight);
18861
+ o.set("rhythmmode", obj.rhythmMode);
18862
+ o.set("rhythmheight", obj.rhythmHeight);
18863
+ o.set("transpositionpitches", obj.transpositionPitches);
18864
+ o.set("displaytranspositionpitches", obj.displayTranspositionPitches);
18865
+ o.set("smallgracetabnotes", obj.smallGraceTabNotes);
18866
+ o.set("extendbendarrowsontiednotes", obj.extendBendArrowsOnTiedNotes);
18867
+ o.set("extendlineeffectstobeatend", obj.extendLineEffectsToBeatEnd);
18868
+ o.set("slurheight", obj.slurHeight);
18745
18869
  return o;
18746
18870
  }
18747
18871
  static setProperty(obj, property, v) {
@@ -18800,8 +18924,8 @@
18800
18924
  }
18801
18925
  const o = new Map();
18802
18926
  o.set("encoding", obj.encoding);
18803
- o.set("mergePartGroupsInMusicXml", obj.mergePartGroupsInMusicXml);
18804
- o.set("beatTextAsLyrics", obj.beatTextAsLyrics);
18927
+ o.set("mergepartgroupsinmusicxml", obj.mergePartGroupsInMusicXml);
18928
+ o.set("beattextaslyrics", obj.beatTextAsLyrics);
18805
18929
  return o;
18806
18930
  }
18807
18931
  static setProperty(obj, property, v) {
@@ -18832,14 +18956,14 @@
18832
18956
  return null;
18833
18957
  }
18834
18958
  const o = new Map();
18835
- o.set("noteWideLength", obj.noteWideLength);
18836
- o.set("noteWideAmplitude", obj.noteWideAmplitude);
18837
- o.set("noteSlightLength", obj.noteSlightLength);
18838
- o.set("noteSlightAmplitude", obj.noteSlightAmplitude);
18839
- o.set("beatWideLength", obj.beatWideLength);
18840
- o.set("beatWideAmplitude", obj.beatWideAmplitude);
18841
- o.set("beatSlightLength", obj.beatSlightLength);
18842
- o.set("beatSlightAmplitude", obj.beatSlightAmplitude);
18959
+ o.set("notewidelength", obj.noteWideLength);
18960
+ o.set("notewideamplitude", obj.noteWideAmplitude);
18961
+ o.set("noteslightlength", obj.noteSlightLength);
18962
+ o.set("noteslightamplitude", obj.noteSlightAmplitude);
18963
+ o.set("beatwidelength", obj.beatWideLength);
18964
+ o.set("beatwideamplitude", obj.beatWideAmplitude);
18965
+ o.set("beatslightlength", obj.beatSlightLength);
18966
+ o.set("beatslightamplitude", obj.beatSlightAmplitude);
18843
18967
  return o;
18844
18968
  }
18845
18969
  static setProperty(obj, property, v) {
@@ -18885,9 +19009,9 @@
18885
19009
  return null;
18886
19010
  }
18887
19011
  const o = new Map();
18888
- o.set("simpleSlidePitchOffset", obj.simpleSlidePitchOffset);
18889
- o.set("simpleSlideDurationRatio", obj.simpleSlideDurationRatio);
18890
- o.set("shiftSlideDurationRatio", obj.shiftSlideDurationRatio);
19012
+ o.set("simpleslidepitchoffset", obj.simpleSlidePitchOffset);
19013
+ o.set("simpleslidedurationratio", obj.simpleSlideDurationRatio);
19014
+ o.set("shiftslidedurationratio", obj.shiftSlideDurationRatio);
18891
19015
  return o;
18892
19016
  }
18893
19017
  static setProperty(obj, property, v) {
@@ -18918,24 +19042,24 @@
18918
19042
  return null;
18919
19043
  }
18920
19044
  const o = new Map();
18921
- o.set("soundFont", obj.soundFont);
18922
- o.set("scrollElement", obj.scrollElement);
18923
- o.set("enablePlayer", obj.enablePlayer);
18924
- o.set("enableCursor", obj.enableCursor);
18925
- o.set("enableAnimatedBeatCursor", obj.enableAnimatedBeatCursor);
18926
- o.set("enableElementHighlighting", obj.enableElementHighlighting);
18927
- o.set("enableUserInteraction", obj.enableUserInteraction);
18928
- o.set("scrollOffsetX", obj.scrollOffsetX);
18929
- o.set("scrollOffsetY", obj.scrollOffsetY);
18930
- o.set("scrollMode", obj.scrollMode);
18931
- o.set("scrollSpeed", obj.scrollSpeed);
19045
+ o.set("soundfont", obj.soundFont);
19046
+ o.set("scrollelement", obj.scrollElement);
19047
+ o.set("enableplayer", obj.enablePlayer);
19048
+ o.set("enablecursor", obj.enableCursor);
19049
+ o.set("enableanimatedbeatcursor", obj.enableAnimatedBeatCursor);
19050
+ o.set("enableelementhighlighting", obj.enableElementHighlighting);
19051
+ o.set("enableuserinteraction", obj.enableUserInteraction);
19052
+ o.set("scrolloffsetx", obj.scrollOffsetX);
19053
+ o.set("scrolloffsety", obj.scrollOffsetY);
19054
+ o.set("scrollmode", obj.scrollMode);
19055
+ o.set("scrollspeed", obj.scrollSpeed);
18932
19056
  /*@target web*/
18933
- o.set("nativeBrowserSmoothScroll", obj.nativeBrowserSmoothScroll);
18934
- o.set("songBookBendDuration", obj.songBookBendDuration);
18935
- o.set("songBookDipDuration", obj.songBookDipDuration);
19057
+ o.set("nativebrowsersmoothscroll", obj.nativeBrowserSmoothScroll);
19058
+ o.set("songbookbendduration", obj.songBookBendDuration);
19059
+ o.set("songbookdipduration", obj.songBookDipDuration);
18936
19060
  o.set("vibrato", VibratoPlaybackSettingsSerializer.toJson(obj.vibrato));
18937
19061
  o.set("slide", SlidePlaybackSettingsSerializer.toJson(obj.slide));
18938
- o.set("playTripletFeel", obj.playTripletFeel);
19062
+ o.set("playtripletfeel", obj.playTripletFeel);
18939
19063
  return o;
18940
19064
  }
18941
19065
  static setProperty(obj, property, v) {
@@ -19197,7 +19321,7 @@
19197
19321
  if (!m) {
19198
19322
  return;
19199
19323
  }
19200
- JsonHelper.forEach(m, (v, k) => this.setProperty(obj, k.toLowerCase(), v));
19324
+ JsonHelper.forEach(m, (v, k) => this.setProperty(obj, k, v));
19201
19325
  }
19202
19326
  static toJson(obj) {
19203
19327
  if (!obj) {
@@ -19226,17 +19350,17 @@
19226
19350
  if (!m) {
19227
19351
  return;
19228
19352
  }
19229
- JsonHelper.forEach(m, (v, k) => this.setProperty(obj, k.toLowerCase(), v));
19353
+ JsonHelper.forEach(m, (v, k) => this.setProperty(obj, k, v));
19230
19354
  }
19231
19355
  static toJson(obj) {
19232
19356
  if (!obj) {
19233
19357
  return null;
19234
19358
  }
19235
19359
  const o = new Map();
19236
- o.set("isLinear", obj.isLinear);
19360
+ o.set("islinear", obj.isLinear);
19237
19361
  o.set("type", obj.type);
19238
19362
  o.set("value", obj.value);
19239
- o.set("ratioPosition", obj.ratioPosition);
19363
+ o.set("ratioposition", obj.ratioPosition);
19240
19364
  o.set("text", obj.text);
19241
19365
  return o;
19242
19366
  }
@@ -19267,7 +19391,7 @@
19267
19391
  if (!m) {
19268
19392
  return;
19269
19393
  }
19270
- JsonHelper.forEach(m, (v, k) => this.setProperty(obj, k.toLowerCase(), v));
19394
+ JsonHelper.forEach(m, (v, k) => this.setProperty(obj, k, v));
19271
19395
  }
19272
19396
  static toJson(obj) {
19273
19397
  if (!obj) {
@@ -19296,26 +19420,26 @@
19296
19420
  if (!m) {
19297
19421
  return;
19298
19422
  }
19299
- JsonHelper.forEach(m, (v, k) => this.setProperty(obj, k.toLowerCase(), v));
19423
+ JsonHelper.forEach(m, (v, k) => this.setProperty(obj, k, v));
19300
19424
  }
19301
19425
  static toJson(obj) {
19302
19426
  if (!obj) {
19303
19427
  return null;
19304
19428
  }
19305
19429
  const o = new Map();
19306
- o.set("alternateEndings", obj.alternateEndings);
19307
- o.set("keySignature", obj.keySignature);
19308
- o.set("keySignatureType", obj.keySignatureType);
19309
- o.set("isDoubleBar", obj.isDoubleBar);
19310
- o.set("isRepeatStart", obj.isRepeatStart);
19311
- o.set("repeatCount", obj.repeatCount);
19312
- o.set("timeSignatureNumerator", obj.timeSignatureNumerator);
19313
- o.set("timeSignatureDenominator", obj.timeSignatureDenominator);
19314
- o.set("timeSignatureCommon", obj.timeSignatureCommon);
19315
- o.set("tripletFeel", obj.tripletFeel);
19430
+ o.set("alternateendings", obj.alternateEndings);
19431
+ o.set("keysignature", obj.keySignature);
19432
+ o.set("keysignaturetype", obj.keySignatureType);
19433
+ o.set("isdoublebar", obj.isDoubleBar);
19434
+ o.set("isrepeatstart", obj.isRepeatStart);
19435
+ o.set("repeatcount", obj.repeatCount);
19436
+ o.set("timesignaturenumerator", obj.timeSignatureNumerator);
19437
+ o.set("timesignaturedenominator", obj.timeSignatureDenominator);
19438
+ o.set("timesignaturecommon", obj.timeSignatureCommon);
19439
+ o.set("tripletfeel", obj.tripletFeel);
19316
19440
  o.set("section", SectionSerializer.toJson(obj.section));
19317
- o.set("tempoAutomation", AutomationSerializer.toJson(obj.tempoAutomation));
19318
- {
19441
+ o.set("tempoautomation", AutomationSerializer.toJson(obj.tempoAutomation));
19442
+ if (obj.fermata !== null) {
19319
19443
  const m = new Map();
19320
19444
  o.set("fermata", m);
19321
19445
  for (const [k, v] of obj.fermata) {
@@ -19323,7 +19447,7 @@
19323
19447
  }
19324
19448
  }
19325
19449
  o.set("start", obj.start);
19326
- o.set("isAnacrusis", obj.isAnacrusis);
19450
+ o.set("isanacrusis", obj.isAnacrusis);
19327
19451
  return o;
19328
19452
  }
19329
19453
  static setProperty(obj, property, v) {
@@ -19363,7 +19487,7 @@
19363
19487
  JsonHelper.forEach(v, (v, k) => {
19364
19488
  const i = new Fermata();
19365
19489
  FermataSerializer.fromJson(i, v);
19366
- obj.fermata.set(parseInt(k), i);
19490
+ obj.addFermata(parseInt(k), i);
19367
19491
  });
19368
19492
  return true;
19369
19493
  case "start":
@@ -19402,7 +19526,7 @@
19402
19526
  if (!m) {
19403
19527
  return;
19404
19528
  }
19405
- JsonHelper.forEach(m, (v, k) => this.setProperty(obj, k.toLowerCase(), v));
19529
+ JsonHelper.forEach(m, (v, k) => this.setProperty(obj, k, v));
19406
19530
  }
19407
19531
  static toJson(obj) {
19408
19532
  if (!obj) {
@@ -19431,53 +19555,51 @@
19431
19555
  if (!m) {
19432
19556
  return;
19433
19557
  }
19434
- JsonHelper.forEach(m, (v, k) => this.setProperty(obj, k.toLowerCase(), v));
19558
+ JsonHelper.forEach(m, (v, k) => this.setProperty(obj, k, v));
19435
19559
  }
19436
19560
  static toJson(obj) {
19561
+ var _a;
19437
19562
  if (!obj) {
19438
19563
  return null;
19439
19564
  }
19440
19565
  const o = new Map();
19441
19566
  o.set("id", obj.id);
19442
19567
  o.set("accentuated", obj.accentuated);
19443
- o.set("bendType", obj.bendType);
19444
- o.set("bendStyle", obj.bendStyle);
19445
- o.set("isContinuedBend", obj.isContinuedBend);
19446
- o.set("bendPoints", obj.bendPoints.map(i => BendPointSerializer.toJson(i)));
19568
+ o.set("bendtype", obj.bendType);
19569
+ o.set("bendstyle", obj.bendStyle);
19570
+ o.set("iscontinuedbend", obj.isContinuedBend);
19571
+ if (obj.bendPoints !== null) {
19572
+ o.set("bendpoints", (_a = obj.bendPoints) === null || _a === void 0 ? void 0 : _a.map(i => BendPointSerializer.toJson(i)));
19573
+ }
19447
19574
  o.set("fret", obj.fret);
19448
19575
  o.set("string", obj.string);
19449
19576
  o.set("octave", obj.octave);
19450
19577
  o.set("tone", obj.tone);
19451
- o.set("percussionArticulation", obj.percussionArticulation);
19452
- o.set("isVisible", obj.isVisible);
19453
- o.set("isLeftHandTapped", obj.isLeftHandTapped);
19454
- o.set("isHammerPullOrigin", obj.isHammerPullOrigin);
19455
- o.set("hammerPullOriginNoteId", obj.hammerPullOriginNoteId);
19456
- o.set("hammerPullDestinationNoteId", obj.hammerPullDestinationNoteId);
19457
- o.set("isSlurDestination", obj.isSlurDestination);
19458
- o.set("slurOriginNoteId", obj.slurOriginNoteId);
19459
- o.set("slurDestinationNoteId", obj.slurDestinationNoteId);
19460
- o.set("harmonicType", obj.harmonicType);
19461
- o.set("harmonicValue", obj.harmonicValue);
19462
- o.set("isGhost", obj.isGhost);
19463
- o.set("isLetRing", obj.isLetRing);
19464
- o.set("isPalmMute", obj.isPalmMute);
19465
- o.set("isDead", obj.isDead);
19466
- o.set("isStaccato", obj.isStaccato);
19467
- o.set("slideInType", obj.slideInType);
19468
- o.set("slideOutType", obj.slideOutType);
19578
+ o.set("percussionarticulation", obj.percussionArticulation);
19579
+ o.set("isvisible", obj.isVisible);
19580
+ o.set("islefthandtapped", obj.isLeftHandTapped);
19581
+ o.set("ishammerpullorigin", obj.isHammerPullOrigin);
19582
+ o.set("isslurdestination", obj.isSlurDestination);
19583
+ o.set("harmonictype", obj.harmonicType);
19584
+ o.set("harmonicvalue", obj.harmonicValue);
19585
+ o.set("isghost", obj.isGhost);
19586
+ o.set("isletring", obj.isLetRing);
19587
+ o.set("ispalmmute", obj.isPalmMute);
19588
+ o.set("isdead", obj.isDead);
19589
+ o.set("isstaccato", obj.isStaccato);
19590
+ o.set("slideintype", obj.slideInType);
19591
+ o.set("slideouttype", obj.slideOutType);
19469
19592
  o.set("vibrato", obj.vibrato);
19470
- o.set("tieOriginNoteId", obj.tieOriginNoteId);
19471
- o.set("tieDestinationNoteId", obj.tieDestinationNoteId);
19472
- o.set("isTieDestination", obj.isTieDestination);
19473
- o.set("leftHandFinger", obj.leftHandFinger);
19474
- o.set("rightHandFinger", obj.rightHandFinger);
19475
- o.set("isFingering", obj.isFingering);
19476
- o.set("trillValue", obj.trillValue);
19477
- o.set("trillSpeed", obj.trillSpeed);
19478
- o.set("durationPercent", obj.durationPercent);
19479
- o.set("accidentalMode", obj.accidentalMode);
19593
+ o.set("istiedestination", obj.isTieDestination);
19594
+ o.set("lefthandfinger", obj.leftHandFinger);
19595
+ o.set("righthandfinger", obj.rightHandFinger);
19596
+ o.set("isfingering", obj.isFingering);
19597
+ o.set("trillvalue", obj.trillValue);
19598
+ o.set("trillspeed", obj.trillSpeed);
19599
+ o.set("durationpercent", obj.durationPercent);
19600
+ o.set("accidentalmode", obj.accidentalMode);
19480
19601
  o.set("dynamics", obj.dynamics);
19602
+ obj.toJson(o);
19481
19603
  return o;
19482
19604
  }
19483
19605
  static setProperty(obj, property, v) {
@@ -19498,11 +19620,13 @@
19498
19620
  obj.isContinuedBend = v;
19499
19621
  return true;
19500
19622
  case "bendpoints":
19501
- obj.bendPoints = [];
19502
- for (const o of v) {
19503
- const i = new BendPoint();
19504
- BendPointSerializer.fromJson(i, o);
19505
- obj.addBendPoint(i);
19623
+ if (v) {
19624
+ obj.bendPoints = [];
19625
+ for (const o of v) {
19626
+ const i = new BendPoint();
19627
+ BendPointSerializer.fromJson(i, o);
19628
+ obj.addBendPoint(i);
19629
+ }
19506
19630
  }
19507
19631
  return true;
19508
19632
  case "fret":
@@ -19529,21 +19653,9 @@
19529
19653
  case "ishammerpullorigin":
19530
19654
  obj.isHammerPullOrigin = v;
19531
19655
  return true;
19532
- case "hammerpulloriginnoteid":
19533
- obj.hammerPullOriginNoteId = v;
19534
- return true;
19535
- case "hammerpulldestinationnoteid":
19536
- obj.hammerPullDestinationNoteId = v;
19537
- return true;
19538
19656
  case "isslurdestination":
19539
19657
  obj.isSlurDestination = v;
19540
19658
  return true;
19541
- case "sluroriginnoteid":
19542
- obj.slurOriginNoteId = v;
19543
- return true;
19544
- case "slurdestinationnoteid":
19545
- obj.slurDestinationNoteId = v;
19546
- return true;
19547
19659
  case "harmonictype":
19548
19660
  obj.harmonicType = JsonHelper.parseEnum(v, HarmonicType);
19549
19661
  return true;
@@ -19574,12 +19686,6 @@
19574
19686
  case "vibrato":
19575
19687
  obj.vibrato = JsonHelper.parseEnum(v, VibratoType);
19576
19688
  return true;
19577
- case "tieoriginnoteid":
19578
- obj.tieOriginNoteId = v;
19579
- return true;
19580
- case "tiedestinationnoteid":
19581
- obj.tieDestinationNoteId = v;
19582
- return true;
19583
19689
  case "istiedestination":
19584
19690
  obj.isTieDestination = v;
19585
19691
  return true;
@@ -19608,7 +19714,7 @@
19608
19714
  obj.dynamics = JsonHelper.parseEnum(v, DynamicValue);
19609
19715
  return true;
19610
19716
  }
19611
- return false;
19717
+ return obj.setProperty(property, v);
19612
19718
  }
19613
19719
  }
19614
19720
 
@@ -19617,50 +19723,53 @@
19617
19723
  if (!m) {
19618
19724
  return;
19619
19725
  }
19620
- JsonHelper.forEach(m, (v, k) => this.setProperty(obj, k.toLowerCase(), v));
19726
+ JsonHelper.forEach(m, (v, k) => this.setProperty(obj, k, v));
19621
19727
  }
19622
19728
  static toJson(obj) {
19729
+ var _a;
19623
19730
  if (!obj) {
19624
19731
  return null;
19625
19732
  }
19626
19733
  const o = new Map();
19627
19734
  o.set("id", obj.id);
19628
19735
  o.set("notes", obj.notes.map(i => NoteSerializer.toJson(i)));
19629
- o.set("isEmpty", obj.isEmpty);
19630
- o.set("whammyStyle", obj.whammyStyle);
19736
+ o.set("isempty", obj.isEmpty);
19737
+ o.set("whammystyle", obj.whammyStyle);
19631
19738
  o.set("ottava", obj.ottava);
19632
- o.set("isLegatoOrigin", obj.isLegatoOrigin);
19739
+ o.set("islegatoorigin", obj.isLegatoOrigin);
19633
19740
  o.set("duration", obj.duration);
19634
19741
  o.set("automations", obj.automations.map(i => AutomationSerializer.toJson(i)));
19635
19742
  o.set("dots", obj.dots);
19636
- o.set("fadeIn", obj.fadeIn);
19743
+ o.set("fadein", obj.fadeIn);
19637
19744
  o.set("lyrics", obj.lyrics);
19638
- o.set("hasRasgueado", obj.hasRasgueado);
19745
+ o.set("hasrasgueado", obj.hasRasgueado);
19639
19746
  o.set("pop", obj.pop);
19640
19747
  o.set("slap", obj.slap);
19641
19748
  o.set("tap", obj.tap);
19642
19749
  o.set("text", obj.text);
19643
- o.set("brushType", obj.brushType);
19644
- o.set("brushDuration", obj.brushDuration);
19645
- o.set("tupletDenominator", obj.tupletDenominator);
19646
- o.set("tupletNumerator", obj.tupletNumerator);
19647
- o.set("isContinuedWhammy", obj.isContinuedWhammy);
19648
- o.set("whammyBarType", obj.whammyBarType);
19649
- o.set("whammyBarPoints", obj.whammyBarPoints.map(i => BendPointSerializer.toJson(i)));
19750
+ o.set("brushtype", obj.brushType);
19751
+ o.set("brushduration", obj.brushDuration);
19752
+ o.set("tupletdenominator", obj.tupletDenominator);
19753
+ o.set("tupletnumerator", obj.tupletNumerator);
19754
+ o.set("iscontinuedwhammy", obj.isContinuedWhammy);
19755
+ o.set("whammybartype", obj.whammyBarType);
19756
+ if (obj.whammyBarPoints !== null) {
19757
+ o.set("whammybarpoints", (_a = obj.whammyBarPoints) === null || _a === void 0 ? void 0 : _a.map(i => BendPointSerializer.toJson(i)));
19758
+ }
19650
19759
  o.set("vibrato", obj.vibrato);
19651
- o.set("chordId", obj.chordId);
19652
- o.set("graceType", obj.graceType);
19653
- o.set("pickStroke", obj.pickStroke);
19654
- o.set("tremoloSpeed", obj.tremoloSpeed);
19760
+ o.set("chordid", obj.chordId);
19761
+ o.set("gracetype", obj.graceType);
19762
+ o.set("pickstroke", obj.pickStroke);
19763
+ o.set("tremolospeed", obj.tremoloSpeed);
19655
19764
  o.set("crescendo", obj.crescendo);
19656
- o.set("displayStart", obj.displayStart);
19657
- o.set("playbackStart", obj.playbackStart);
19658
- o.set("displayDuration", obj.displayDuration);
19659
- o.set("playbackDuration", obj.playbackDuration);
19765
+ o.set("displaystart", obj.displayStart);
19766
+ o.set("playbackstart", obj.playbackStart);
19767
+ o.set("displayduration", obj.displayDuration);
19768
+ o.set("playbackduration", obj.playbackDuration);
19660
19769
  o.set("dynamics", obj.dynamics);
19661
- o.set("invertBeamDirection", obj.invertBeamDirection);
19662
- o.set("preferredBeamDirection", obj.preferredBeamDirection);
19663
- o.set("beamingMode", obj.beamingMode);
19770
+ o.set("invertbeamdirection", obj.invertBeamDirection);
19771
+ o.set("preferredbeamdirection", obj.preferredBeamDirection);
19772
+ o.set("beamingmode", obj.beamingMode);
19664
19773
  return o;
19665
19774
  }
19666
19775
  static setProperty(obj, property, v) {
@@ -19742,11 +19851,13 @@
19742
19851
  obj.whammyBarType = JsonHelper.parseEnum(v, WhammyType);
19743
19852
  return true;
19744
19853
  case "whammybarpoints":
19745
- obj.whammyBarPoints = [];
19746
- for (const o of v) {
19747
- const i = new BendPoint();
19748
- BendPointSerializer.fromJson(i, o);
19749
- obj.addWhammyBarPoint(i);
19854
+ if (v) {
19855
+ obj.whammyBarPoints = [];
19856
+ for (const o of v) {
19857
+ const i = new BendPoint();
19858
+ BendPointSerializer.fromJson(i, o);
19859
+ obj.addWhammyBarPoint(i);
19860
+ }
19750
19861
  }
19751
19862
  return true;
19752
19863
  case "vibrato":
@@ -19801,7 +19912,7 @@
19801
19912
  if (!m) {
19802
19913
  return;
19803
19914
  }
19804
- JsonHelper.forEach(m, (v, k) => this.setProperty(obj, k.toLowerCase(), v));
19915
+ JsonHelper.forEach(m, (v, k) => this.setProperty(obj, k, v));
19805
19916
  }
19806
19917
  static toJson(obj) {
19807
19918
  if (!obj) {
@@ -19810,7 +19921,7 @@
19810
19921
  const o = new Map();
19811
19922
  o.set("id", obj.id);
19812
19923
  o.set("beats", obj.beats.map(i => BeatSerializer.toJson(i)));
19813
- o.set("isEmpty", obj.isEmpty);
19924
+ o.set("isempty", obj.isEmpty);
19814
19925
  return o;
19815
19926
  }
19816
19927
  static setProperty(obj, property, v) {
@@ -19839,7 +19950,7 @@
19839
19950
  if (!m) {
19840
19951
  return;
19841
19952
  }
19842
- JsonHelper.forEach(m, (v, k) => this.setProperty(obj, k.toLowerCase(), v));
19953
+ JsonHelper.forEach(m, (v, k) => this.setProperty(obj, k, v));
19843
19954
  }
19844
19955
  static toJson(obj) {
19845
19956
  if (!obj) {
@@ -19848,9 +19959,9 @@
19848
19959
  const o = new Map();
19849
19960
  o.set("id", obj.id);
19850
19961
  o.set("clef", obj.clef);
19851
- o.set("clefOttava", obj.clefOttava);
19962
+ o.set("clefottava", obj.clefOttava);
19852
19963
  o.set("voices", obj.voices.map(i => VoiceSerializer.toJson(i)));
19853
- o.set("simileMark", obj.simileMark);
19964
+ o.set("similemark", obj.simileMark);
19854
19965
  return o;
19855
19966
  }
19856
19967
  static setProperty(obj, property, v) {
@@ -19885,7 +19996,7 @@
19885
19996
  if (!m) {
19886
19997
  return;
19887
19998
  }
19888
- JsonHelper.forEach(m, (v, k) => this.setProperty(obj, k.toLowerCase(), v));
19999
+ JsonHelper.forEach(m, (v, k) => this.setProperty(obj, k, v));
19889
20000
  }
19890
20001
  static toJson(obj) {
19891
20002
  if (!obj) {
@@ -19893,12 +20004,12 @@
19893
20004
  }
19894
20005
  const o = new Map();
19895
20006
  o.set("name", obj.name);
19896
- o.set("firstFret", obj.firstFret);
20007
+ o.set("firstfret", obj.firstFret);
19897
20008
  o.set("strings", obj.strings);
19898
- o.set("barreFrets", obj.barreFrets);
19899
- o.set("showName", obj.showName);
19900
- o.set("showDiagram", obj.showDiagram);
19901
- o.set("showFingering", obj.showFingering);
20009
+ o.set("barrefrets", obj.barreFrets);
20010
+ o.set("showname", obj.showName);
20011
+ o.set("showdiagram", obj.showDiagram);
20012
+ o.set("showfingering", obj.showFingering);
19902
20013
  return o;
19903
20014
  }
19904
20015
  static setProperty(obj, property, v) {
@@ -19934,14 +20045,14 @@
19934
20045
  if (!m) {
19935
20046
  return;
19936
20047
  }
19937
- JsonHelper.forEach(m, (v, k) => this.setProperty(obj, k.toLowerCase(), v));
20048
+ JsonHelper.forEach(m, (v, k) => this.setProperty(obj, k, v));
19938
20049
  }
19939
20050
  static toJson(obj) {
19940
20051
  if (!obj) {
19941
20052
  return null;
19942
20053
  }
19943
20054
  const o = new Map();
19944
- o.set("isStandard", obj.isStandard);
20055
+ o.set("isstandard", obj.isStandard);
19945
20056
  o.set("name", obj.name);
19946
20057
  o.set("tunings", obj.tunings);
19947
20058
  return o;
@@ -19967,7 +20078,7 @@
19967
20078
  if (!m) {
19968
20079
  return;
19969
20080
  }
19970
- JsonHelper.forEach(m, (v, k) => this.setProperty(obj, k.toLowerCase(), v));
20081
+ JsonHelper.forEach(m, (v, k) => this.setProperty(obj, k, v));
19971
20082
  }
19972
20083
  static toJson(obj) {
19973
20084
  if (!obj) {
@@ -19975,7 +20086,7 @@
19975
20086
  }
19976
20087
  const o = new Map();
19977
20088
  o.set("bars", obj.bars.map(i => BarSerializer.toJson(i)));
19978
- {
20089
+ if (obj.chords !== null) {
19979
20090
  const m = new Map();
19980
20091
  o.set("chords", m);
19981
20092
  for (const [k, v] of obj.chords) {
@@ -19983,13 +20094,13 @@
19983
20094
  }
19984
20095
  }
19985
20096
  o.set("capo", obj.capo);
19986
- o.set("transpositionPitch", obj.transpositionPitch);
19987
- o.set("displayTranspositionPitch", obj.displayTranspositionPitch);
19988
- o.set("stringTuning", TuningSerializer.toJson(obj.stringTuning));
19989
- o.set("showTablature", obj.showTablature);
19990
- o.set("showStandardNotation", obj.showStandardNotation);
19991
- o.set("isPercussion", obj.isPercussion);
19992
- o.set("standardNotationLineCount", obj.standardNotationLineCount);
20097
+ o.set("transpositionpitch", obj.transpositionPitch);
20098
+ o.set("displaytranspositionpitch", obj.displayTranspositionPitch);
20099
+ o.set("stringtuning", TuningSerializer.toJson(obj.stringTuning));
20100
+ o.set("showtablature", obj.showTablature);
20101
+ o.set("showstandardnotation", obj.showStandardNotation);
20102
+ o.set("ispercussion", obj.isPercussion);
20103
+ o.set("standardnotationlinecount", obj.standardNotationLineCount);
19993
20104
  return o;
19994
20105
  }
19995
20106
  static setProperty(obj, property, v) {
@@ -20045,7 +20156,7 @@
20045
20156
  if (!m) {
20046
20157
  return;
20047
20158
  }
20048
- JsonHelper.forEach(m, (v, k) => this.setProperty(obj, k.toLowerCase(), v));
20159
+ JsonHelper.forEach(m, (v, k) => this.setProperty(obj, k, v));
20049
20160
  }
20050
20161
  static toJson(obj) {
20051
20162
  if (!obj) {
@@ -20056,10 +20167,10 @@
20056
20167
  o.set("balance", obj.balance);
20057
20168
  o.set("port", obj.port);
20058
20169
  o.set("program", obj.program);
20059
- o.set("primaryChannel", obj.primaryChannel);
20060
- o.set("secondaryChannel", obj.secondaryChannel);
20061
- o.set("isMute", obj.isMute);
20062
- o.set("isSolo", obj.isSolo);
20170
+ o.set("primarychannel", obj.primaryChannel);
20171
+ o.set("secondarychannel", obj.secondaryChannel);
20172
+ o.set("ismute", obj.isMute);
20173
+ o.set("issolo", obj.isSolo);
20063
20174
  return o;
20064
20175
  }
20065
20176
  static setProperty(obj, property, v) {
@@ -20098,21 +20209,21 @@
20098
20209
  if (!m) {
20099
20210
  return;
20100
20211
  }
20101
- JsonHelper.forEach(m, (v, k) => this.setProperty(obj, k.toLowerCase(), v));
20212
+ JsonHelper.forEach(m, (v, k) => this.setProperty(obj, k, v));
20102
20213
  }
20103
20214
  static toJson(obj) {
20104
20215
  if (!obj) {
20105
20216
  return null;
20106
20217
  }
20107
20218
  const o = new Map();
20108
- o.set("elementType", obj.elementType);
20109
- o.set("staffLine", obj.staffLine);
20110
- o.set("noteHeadDefault", obj.noteHeadDefault);
20111
- o.set("noteHeadHalf", obj.noteHeadHalf);
20112
- o.set("noteHeadWhole", obj.noteHeadWhole);
20113
- o.set("techniqueSymbol", obj.techniqueSymbol);
20114
- o.set("techniqueSymbolPlacement", obj.techniqueSymbolPlacement);
20115
- o.set("outputMidiNumber", obj.outputMidiNumber);
20219
+ o.set("elementtype", obj.elementType);
20220
+ o.set("staffline", obj.staffLine);
20221
+ o.set("noteheaddefault", obj.noteHeadDefault);
20222
+ o.set("noteheadhalf", obj.noteHeadHalf);
20223
+ o.set("noteheadwhole", obj.noteHeadWhole);
20224
+ o.set("techniquesymbol", obj.techniqueSymbol);
20225
+ o.set("techniquesymbolplacement", obj.techniqueSymbolPlacement);
20226
+ o.set("outputmidinumber", obj.outputMidiNumber);
20116
20227
  return o;
20117
20228
  }
20118
20229
  static setProperty(obj, property, v) {
@@ -20151,7 +20262,7 @@
20151
20262
  if (!m) {
20152
20263
  return;
20153
20264
  }
20154
- JsonHelper.forEach(m, (v, k) => this.setProperty(obj, k.toLowerCase(), v));
20265
+ JsonHelper.forEach(m, (v, k) => this.setProperty(obj, k, v));
20155
20266
  }
20156
20267
  static toJson(obj) {
20157
20268
  if (!obj) {
@@ -20159,11 +20270,11 @@
20159
20270
  }
20160
20271
  const o = new Map();
20161
20272
  o.set("staves", obj.staves.map(i => StaffSerializer.toJson(i)));
20162
- o.set("playbackInfo", PlaybackInformationSerializer.toJson(obj.playbackInfo));
20273
+ o.set("playbackinfo", PlaybackInformationSerializer.toJson(obj.playbackInfo));
20163
20274
  o.set("color", Color.toJson(obj.color));
20164
20275
  o.set("name", obj.name);
20165
- o.set("shortName", obj.shortName);
20166
- o.set("percussionArticulations", obj.percussionArticulations.map(i => InstrumentArticulationSerializer.toJson(i)));
20276
+ o.set("shortname", obj.shortName);
20277
+ o.set("percussionarticulations", obj.percussionArticulations.map(i => InstrumentArticulationSerializer.toJson(i)));
20167
20278
  return o;
20168
20279
  }
20169
20280
  static setProperty(obj, property, v) {
@@ -20207,14 +20318,14 @@
20207
20318
  if (!m) {
20208
20319
  return;
20209
20320
  }
20210
- JsonHelper.forEach(m, (v, k) => this.setProperty(obj, k.toLowerCase(), v));
20321
+ JsonHelper.forEach(m, (v, k) => this.setProperty(obj, k, v));
20211
20322
  }
20212
20323
  static toJson(obj) {
20213
20324
  if (!obj) {
20214
20325
  return null;
20215
20326
  }
20216
20327
  const o = new Map();
20217
- o.set("hideDynamics", obj.hideDynamics);
20328
+ o.set("hidedynamics", obj.hideDynamics);
20218
20329
  return o;
20219
20330
  }
20220
20331
  static setProperty(obj, property, v) {
@@ -20232,7 +20343,7 @@
20232
20343
  if (!m) {
20233
20344
  return;
20234
20345
  }
20235
- JsonHelper.forEach(m, (v, k) => this.setProperty(obj, k.toLowerCase(), v));
20346
+ JsonHelper.forEach(m, (v, k) => this.setProperty(obj, k, v));
20236
20347
  }
20237
20348
  static toJson(obj) {
20238
20349
  if (!obj) {
@@ -20245,13 +20356,13 @@
20245
20356
  o.set("instructions", obj.instructions);
20246
20357
  o.set("music", obj.music);
20247
20358
  o.set("notices", obj.notices);
20248
- o.set("subTitle", obj.subTitle);
20359
+ o.set("subtitle", obj.subTitle);
20249
20360
  o.set("title", obj.title);
20250
20361
  o.set("words", obj.words);
20251
20362
  o.set("tab", obj.tab);
20252
20363
  o.set("tempo", obj.tempo);
20253
- o.set("tempoLabel", obj.tempoLabel);
20254
- o.set("masterBars", obj.masterBars.map(i => MasterBarSerializer.toJson(i)));
20364
+ o.set("tempolabel", obj.tempoLabel);
20365
+ o.set("masterbars", obj.masterBars.map(i => MasterBarSerializer.toJson(i)));
20255
20366
  o.set("tracks", obj.tracks.map(i => TrackSerializer.toJson(i)));
20256
20367
  o.set("stylesheet", RenderStylesheetSerializer.toJson(obj.stylesheet));
20257
20368
  return o;
@@ -20862,6 +20973,18 @@
20862
20973
  */
20863
20974
  class RenderFinishedEventArgs {
20864
20975
  constructor() {
20976
+ /**
20977
+ * Gets or sets the unique id of this event args.
20978
+ */
20979
+ this.id = ModelUtils.newGuid();
20980
+ /**
20981
+ * Gets or sets the x position of the current rendering result.
20982
+ */
20983
+ this.x = 0;
20984
+ /**
20985
+ * Gets or sets the y position of the current rendering result.
20986
+ */
20987
+ this.y = 0;
20865
20988
  /**
20866
20989
  * Gets or sets the width of the current rendering result.
20867
20990
  */
@@ -21394,12 +21517,16 @@
21394
21517
  this.canvas = null;
21395
21518
  this.score = null;
21396
21519
  this.tracks = null;
21520
+ /**
21521
+ * @internal
21522
+ */
21397
21523
  this.layout = null;
21398
21524
  this.boundsLookup = null;
21399
21525
  this.width = 0;
21400
21526
  this.preRender = new EventEmitterOfT();
21401
21527
  this.renderFinished = new EventEmitterOfT();
21402
21528
  this.partialRenderFinished = new EventEmitterOfT();
21529
+ this.partialLayoutFinished = new EventEmitterOfT();
21403
21530
  this.postRenderFinished = new EventEmitter();
21404
21531
  this.error = new EventEmitterOfT();
21405
21532
  this.settings = settings;
@@ -21432,20 +21559,22 @@
21432
21559
  renderScore(score, trackIndexes) {
21433
21560
  try {
21434
21561
  this.score = score;
21435
- let tracks;
21436
- if (!trackIndexes) {
21437
- tracks = score.tracks.slice(0);
21438
- }
21439
- else {
21440
- tracks = [];
21441
- for (let track of trackIndexes) {
21442
- if (track >= 0 && track < score.tracks.length) {
21443
- tracks.push(score.tracks[track]);
21562
+ let tracks = null;
21563
+ if (score != null && trackIndexes != null) {
21564
+ if (!trackIndexes) {
21565
+ tracks = score.tracks.slice(0);
21566
+ }
21567
+ else {
21568
+ tracks = [];
21569
+ for (let track of trackIndexes) {
21570
+ if (track >= 0 && track < score.tracks.length) {
21571
+ tracks.push(score.tracks[track]);
21572
+ }
21444
21573
  }
21445
21574
  }
21446
- }
21447
- if (tracks.length === 0 && score.tracks.length > 0) {
21448
- tracks.push(score.tracks[0]);
21575
+ if (tracks.length === 0 && score.tracks.length > 0) {
21576
+ tracks.push(score.tracks[0]);
21577
+ }
21449
21578
  }
21450
21579
  this.tracks = tracks;
21451
21580
  this.render();
@@ -21471,27 +21600,49 @@
21471
21600
  updateSettings(settings) {
21472
21601
  this.settings = settings;
21473
21602
  }
21603
+ renderResult(resultId) {
21604
+ try {
21605
+ const layout = this.layout;
21606
+ if (layout) {
21607
+ Logger.debug('Rendering', 'Request render of lazy partial ' + resultId);
21608
+ layout.renderLazyPartial(resultId);
21609
+ }
21610
+ else {
21611
+ Logger.warning('Rendering', 'Request render of lazy partial ' + resultId + ' ignored, no layout exists');
21612
+ }
21613
+ }
21614
+ catch (e) {
21615
+ this.error.trigger(e);
21616
+ }
21617
+ }
21474
21618
  render() {
21475
21619
  if (this.width === 0) {
21476
21620
  Logger.warning('Rendering', 'AlphaTab skipped rendering because of width=0 (element invisible)', null);
21477
21621
  return;
21478
21622
  }
21479
21623
  this.boundsLookup = new BoundsLookup();
21480
- if (!this.tracks || this.tracks.length === 0) {
21481
- return;
21482
- }
21483
21624
  this.recreateCanvas();
21484
21625
  this.canvas.lineWidth = this.settings.display.scale;
21485
21626
  this.canvas.settings = this.settings;
21486
- Logger.debug('Rendering', 'Rendering ' + this.tracks.length + ' tracks');
21487
- for (let i = 0; i < this.tracks.length; i++) {
21488
- let track = this.tracks[i];
21489
- Logger.debug('Rendering', 'Track ' + i + ': ' + track.name);
21627
+ if (!this.tracks || this.tracks.length === 0 || !this.score) {
21628
+ Logger.debug('Rendering', 'Clearing rendered tracks because no score or tracks are set');
21629
+ this.preRender.trigger(false);
21630
+ this._renderedTracks = null;
21631
+ this.onRenderFinished();
21632
+ this.postRenderFinished.trigger();
21633
+ Logger.debug('Rendering', 'Clearing finished');
21634
+ }
21635
+ else {
21636
+ Logger.debug('Rendering', 'Rendering ' + this.tracks.length + ' tracks');
21637
+ for (let i = 0; i < this.tracks.length; i++) {
21638
+ let track = this.tracks[i];
21639
+ Logger.debug('Rendering', 'Track ' + i + ': ' + track.name);
21640
+ }
21641
+ this.preRender.trigger(false);
21642
+ this.recreateLayout();
21643
+ this.layoutAndRender();
21644
+ Logger.debug('Rendering', 'Rendering finished');
21490
21645
  }
21491
- this.preRender.trigger(false);
21492
- this.recreateLayout();
21493
- this.layoutAndRender();
21494
- Logger.debug('Rendering', 'Rendering finished');
21495
21646
  }
21496
21647
  resizeRender() {
21497
21648
  if (this.recreateLayout() || this.recreateCanvas() || this._renderedTracks !== this.tracks || !this.tracks) {
@@ -21504,7 +21655,6 @@
21504
21655
  this.preRender.trigger(true);
21505
21656
  this.canvas.settings = this.settings;
21506
21657
  this.layout.resize();
21507
- this.layout.renderAnnotation();
21508
21658
  this.onRenderFinished();
21509
21659
  this.postRenderFinished.trigger();
21510
21660
  }
@@ -21516,7 +21666,6 @@
21516
21666
  layoutAndRender() {
21517
21667
  Logger.debug('Rendering', 'Rendering at scale ' + this.settings.display.scale + ' with layout ' + this.layout.name, null);
21518
21668
  this.layout.layoutAndRender();
21519
- this.layout.renderAnnotation();
21520
21669
  this._renderedTracks = this.tracks;
21521
21670
  this.onRenderFinished();
21522
21671
  this.postRenderFinished.trigger();
@@ -21555,6 +21704,12 @@
21555
21704
  result: result
21556
21705
  });
21557
21706
  });
21707
+ this._renderer.partialLayoutFinished.on(result => {
21708
+ this._main.postMessage({
21709
+ cmd: 'alphaTab.partialLayoutFinished',
21710
+ result: result
21711
+ });
21712
+ });
21558
21713
  this._renderer.renderFinished.on(result => {
21559
21714
  this._main.postMessage({
21560
21715
  cmd: 'alphaTab.renderFinished',
@@ -21582,12 +21737,15 @@
21582
21737
  case 'alphaTab.resizeRender':
21583
21738
  this._renderer.resizeRender();
21584
21739
  break;
21740
+ case 'alphaTab.renderResult':
21741
+ this._renderer.renderResult(data.resultId);
21742
+ break;
21585
21743
  case 'alphaTab.setWidth':
21586
21744
  this._renderer.width = data.width;
21587
21745
  break;
21588
21746
  case 'alphaTab.renderScore':
21589
21747
  this.updateFontSizes(data.fontSizes);
21590
- let score = JsonConverter.jsObjectToScore(data.score, this._renderer.settings);
21748
+ let score = data.score == null ? null : JsonConverter.jsObjectToScore(data.score, this._renderer.settings);
21591
21749
  this.renderMultiple(score, data.trackIndexes);
21592
21750
  break;
21593
21751
  case 'alphaTab.updateSettings':
@@ -23888,6 +24046,7 @@
23888
24046
  this._previousTick = 0;
23889
24047
  this._playerState = PlayerState.Paused;
23890
24048
  this._currentBeat = null;
24049
+ this._currentBarBounds = null;
23891
24050
  this._previousStateForCursor = PlayerState.Paused;
23892
24051
  this._previousCursorCache = null;
23893
24052
  this._lastScroll = 0;
@@ -23951,7 +24110,8 @@
23951
24110
  this.renderer.preRender.on(_ => {
23952
24111
  this._startTime = Date.now();
23953
24112
  });
23954
- this.renderer.partialRenderFinished.on(this.appendRenderResult.bind(this));
24113
+ this.renderer.partialLayoutFinished.on(this.appendRenderResult.bind(this));
24114
+ this.renderer.partialRenderFinished.on(this.updateRenderResult.bind(this));
23955
24115
  this.renderer.renderFinished.on(r => {
23956
24116
  this.appendRenderResult(r);
23957
24117
  this.appendRenderResult(null); // marks last element
@@ -24113,8 +24273,11 @@
24113
24273
  this._cursorWrapper.height = result.totalHeight;
24114
24274
  }
24115
24275
  }
24116
- if (!result || result.renderResult) {
24117
- this.uiFacade.beginAppendRenderResults(result);
24276
+ this.uiFacade.beginAppendRenderResults(result);
24277
+ }
24278
+ updateRenderResult(result) {
24279
+ if (result && result.renderResult) {
24280
+ this.uiFacade.beginUpdateRenderResults(result);
24118
24281
  }
24119
24282
  }
24120
24283
  /**
@@ -24486,7 +24649,7 @@
24486
24649
  this._playerState = PlayerState.Paused;
24487
24650
  // we need to update our position caches if we render a tablature
24488
24651
  this.renderer.postRenderFinished.on(() => {
24489
- this.cursorUpdateTick(this._previousTick, false);
24652
+ this.cursorUpdateTick(this._previousTick, false, this._previousTick > 10);
24490
24653
  });
24491
24654
  if (this.player) {
24492
24655
  this.player.positionChanged.on(e => {
@@ -24513,15 +24676,16 @@
24513
24676
  * updates the cursors to highlight the beat at the specified tick position
24514
24677
  * @param tick
24515
24678
  * @param stop
24679
+ * @param shouldScroll whether we should scroll to the bar (if scrolling is active)
24516
24680
  */
24517
- cursorUpdateTick(tick, stop) {
24681
+ cursorUpdateTick(tick, stop, shouldScroll = false) {
24518
24682
  let cache = this._tickCache;
24519
24683
  if (cache) {
24520
24684
  let tracks = this.tracks;
24521
24685
  if (tracks.length > 0) {
24522
24686
  let beat = cache.findBeat(tracks, tick, this._currentBeat);
24523
24687
  if (beat) {
24524
- this.cursorUpdateBeat(beat, stop);
24688
+ this.cursorUpdateBeat(beat, stop, shouldScroll);
24525
24689
  }
24526
24690
  }
24527
24691
  }
@@ -24529,7 +24693,7 @@
24529
24693
  /**
24530
24694
  * updates the cursors to highlight the specified beat
24531
24695
  */
24532
- cursorUpdateBeat(lookupResult, stop) {
24696
+ cursorUpdateBeat(lookupResult, stop, shouldScroll) {
24533
24697
  const beat = lookupResult.currentBeat;
24534
24698
  const nextBeat = lookupResult.nextBeat;
24535
24699
  const duration = lookupResult.duration;
@@ -24544,9 +24708,6 @@
24544
24708
  let previousBeat = this._currentBeat;
24545
24709
  let previousCache = this._previousCursorCache;
24546
24710
  let previousState = this._previousStateForCursor;
24547
- this._currentBeat = lookupResult;
24548
- this._previousCursorCache = cache;
24549
- this._previousStateForCursor = this._playerState;
24550
24711
  if (beat === (previousBeat === null || previousBeat === void 0 ? void 0 : previousBeat.currentBeat) && cache === previousCache && previousState === this._playerState) {
24551
24712
  return;
24552
24713
  }
@@ -24554,15 +24715,81 @@
24554
24715
  if (!beatBoundings) {
24555
24716
  return;
24556
24717
  }
24718
+ // only if we really found some bounds we remember the beat and cache we used to
24719
+ // actually show the cursor
24720
+ this._currentBeat = lookupResult;
24721
+ this._previousCursorCache = cache;
24722
+ this._previousStateForCursor = this._playerState;
24557
24723
  this.uiFacade.beginInvoke(() => {
24558
- this.internalCursorUpdateBeat(beat, nextBeat, duration, stop, beatsToHighlight, cache, beatBoundings);
24724
+ this.internalCursorUpdateBeat(beat, nextBeat, duration, stop, beatsToHighlight, cache, beatBoundings, shouldScroll);
24559
24725
  });
24560
24726
  }
24561
- internalCursorUpdateBeat(beat, nextBeat, duration, stop, beatsToHighlight, cache, beatBoundings) {
24727
+ /**
24728
+ * Initiates a scroll to the cursor
24729
+ */
24730
+ scrollToCursor() {
24731
+ const barBounds = this._currentBarBounds;
24732
+ if (barBounds) {
24733
+ this.internalScrollToCursor(barBounds);
24734
+ }
24735
+ }
24736
+ internalScrollToCursor(barBoundings) {
24737
+ let scrollElement = this.uiFacade.getScrollContainer();
24738
+ let isVertical = Environment.getLayoutEngineFactory(this.settings.display.layoutMode).vertical;
24739
+ let mode = this.settings.player.scrollMode;
24740
+ if (isVertical) {
24741
+ // when scrolling on the y-axis, we preliminary check if the new beat/bar have
24742
+ // moved on the y-axis
24743
+ let y = barBoundings.realBounds.y + this.settings.player.scrollOffsetY;
24744
+ if (y !== this._lastScroll) {
24745
+ this._lastScroll = y;
24746
+ switch (mode) {
24747
+ case exports.ScrollMode.Continuous:
24748
+ let elementOffset = this.uiFacade.getOffset(scrollElement, this.container);
24749
+ this.uiFacade.scrollToY(scrollElement, elementOffset.y + y, this.settings.player.scrollSpeed);
24750
+ break;
24751
+ case exports.ScrollMode.OffScreen:
24752
+ let elementBottom = scrollElement.scrollTop + this.uiFacade.getOffset(null, scrollElement).h;
24753
+ if (barBoundings.visualBounds.y + barBoundings.visualBounds.h >= elementBottom ||
24754
+ barBoundings.visualBounds.y < scrollElement.scrollTop) {
24755
+ let scrollTop = barBoundings.realBounds.y + this.settings.player.scrollOffsetY;
24756
+ this.uiFacade.scrollToY(scrollElement, scrollTop, this.settings.player.scrollSpeed);
24757
+ }
24758
+ break;
24759
+ }
24760
+ }
24761
+ }
24762
+ else {
24763
+ // when scrolling on the x-axis, we preliminary check if the new bar has
24764
+ // moved on the x-axis
24765
+ let x = barBoundings.visualBounds.x;
24766
+ if (x !== this._lastScroll) {
24767
+ this._lastScroll = x;
24768
+ switch (mode) {
24769
+ case exports.ScrollMode.Continuous:
24770
+ let scrollLeftContinuous = barBoundings.realBounds.x + this.settings.player.scrollOffsetX;
24771
+ this._lastScroll = barBoundings.visualBounds.x;
24772
+ this.uiFacade.scrollToX(scrollElement, scrollLeftContinuous, this.settings.player.scrollSpeed);
24773
+ break;
24774
+ case exports.ScrollMode.OffScreen:
24775
+ let elementRight = scrollElement.scrollLeft + this.uiFacade.getOffset(null, scrollElement).w;
24776
+ if (barBoundings.visualBounds.x + barBoundings.visualBounds.w >= elementRight ||
24777
+ barBoundings.visualBounds.x < scrollElement.scrollLeft) {
24778
+ let scrollLeftOffScreen = barBoundings.realBounds.x + this.settings.player.scrollOffsetX;
24779
+ this._lastScroll = barBoundings.visualBounds.x;
24780
+ this.uiFacade.scrollToX(scrollElement, scrollLeftOffScreen, this.settings.player.scrollSpeed);
24781
+ }
24782
+ break;
24783
+ }
24784
+ }
24785
+ }
24786
+ }
24787
+ internalCursorUpdateBeat(beat, nextBeat, duration, stop, beatsToHighlight, cache, beatBoundings, shouldScroll) {
24562
24788
  let barCursor = this._barCursor;
24563
24789
  let beatCursor = this._beatCursor;
24564
24790
  let barBoundings = beatBoundings.barBounds.masterBarBounds;
24565
24791
  let barBounds = barBoundings.visualBounds;
24792
+ this._currentBarBounds = barBoundings;
24566
24793
  barCursor.setBounds(barBounds.x, barBounds.y, barBounds.w, barBounds.h);
24567
24794
  // move beat to start position immediately
24568
24795
  if (this.settings.player.enableAnimatedBeatCursor) {
@@ -24573,90 +24800,45 @@
24573
24800
  if (this.settings.player.enableElementHighlighting) {
24574
24801
  this.uiFacade.removeHighlights();
24575
24802
  }
24576
- if (this._playerState === PlayerState.Playing || stop) {
24577
- duration /= this.playbackSpeed;
24578
- if (!stop) {
24579
- if (this.settings.player.enableElementHighlighting && beatsToHighlight) {
24580
- for (let highlight of beatsToHighlight) {
24581
- let className = BeatContainerGlyph.getGroupId(highlight);
24582
- this.uiFacade.highlightElements(className, beat.voice.bar.index);
24583
- }
24584
- }
24585
- if (this.settings.player.enableAnimatedBeatCursor) {
24586
- let nextBeatX = barBoundings.visualBounds.x + barBoundings.visualBounds.w;
24587
- // get position of next beat on same stavegroup
24588
- if (nextBeat) {
24589
- // if we are moving within the same bar or to the next bar
24590
- // transition to the next beat, otherwise transition to the end of the bar.
24591
- if ((nextBeat.voice.bar.index === beat.voice.bar.index && nextBeat.index > beat.index) ||
24592
- nextBeat.voice.bar.index === beat.voice.bar.index + 1) {
24593
- let nextBeatBoundings = cache.findBeat(nextBeat);
24594
- if (nextBeatBoundings &&
24595
- nextBeatBoundings.barBounds.masterBarBounds.staveGroupBounds ===
24596
- barBoundings.staveGroupBounds) {
24597
- nextBeatX = nextBeatBoundings.visualBounds.x;
24598
- }
24599
- }
24600
- }
24601
- // we need to put the transition to an own animation frame
24602
- // otherwise the stop animation above is not applied.
24603
- this.uiFacade.beginInvoke(() => {
24604
- beatCursor.transitionToX(duration, nextBeatX);
24605
- });
24606
- }
24607
- }
24608
- if (!this._beatMouseDown && this.settings.player.scrollMode !== exports.ScrollMode.Off) {
24609
- let scrollElement = this.uiFacade.getScrollContainer();
24610
- let isVertical = Environment.getLayoutEngineFactory(this.settings.display.layoutMode).vertical;
24611
- let mode = this.settings.player.scrollMode;
24612
- if (isVertical) {
24613
- // when scrolling on the y-axis, we preliminary check if the new beat/bar have
24614
- // moved on the y-axis
24615
- let y = barBoundings.realBounds.y + this.settings.player.scrollOffsetY;
24616
- if (y !== this._lastScroll) {
24617
- this._lastScroll = y;
24618
- switch (mode) {
24619
- case exports.ScrollMode.Continuous:
24620
- let elementOffset = this.uiFacade.getOffset(scrollElement, this.container);
24621
- this.uiFacade.scrollToY(scrollElement, elementOffset.y + y, this.settings.player.scrollSpeed);
24622
- break;
24623
- case exports.ScrollMode.OffScreen:
24624
- let elementBottom = scrollElement.scrollTop + this.uiFacade.getOffset(null, scrollElement).h;
24625
- if (barBoundings.visualBounds.y + barBoundings.visualBounds.h >= elementBottom ||
24626
- barBoundings.visualBounds.y < scrollElement.scrollTop) {
24627
- let scrollTop = barBoundings.realBounds.y + this.settings.player.scrollOffsetY;
24628
- this.uiFacade.scrollToY(scrollElement, scrollTop, this.settings.player.scrollSpeed);
24629
- }
24630
- break;
24631
- }
24632
- }
24633
- }
24634
- else {
24635
- // when scrolling on the x-axis, we preliminary check if the new bar has
24636
- // moved on the x-axis
24637
- let x = barBoundings.visualBounds.x;
24638
- if (x !== this._lastScroll) {
24639
- this._lastScroll = x;
24640
- switch (mode) {
24641
- case exports.ScrollMode.Continuous:
24642
- let scrollLeftContinuous = barBoundings.realBounds.x + this.settings.player.scrollOffsetX;
24643
- this._lastScroll = barBoundings.visualBounds.x;
24644
- this.uiFacade.scrollToX(scrollElement, scrollLeftContinuous, this.settings.player.scrollSpeed);
24645
- break;
24646
- case exports.ScrollMode.OffScreen:
24647
- let elementRight = scrollElement.scrollLeft + this.uiFacade.getOffset(null, scrollElement).w;
24648
- if (barBoundings.visualBounds.x + barBoundings.visualBounds.w >= elementRight ||
24649
- barBoundings.visualBounds.x < scrollElement.scrollLeft) {
24650
- let scrollLeftOffScreen = barBoundings.realBounds.x + this.settings.player.scrollOffsetX;
24651
- this._lastScroll = barBoundings.visualBounds.x;
24652
- this.uiFacade.scrollToX(scrollElement, scrollLeftOffScreen, this.settings.player.scrollSpeed);
24653
- }
24654
- break;
24803
+ // actively playing? -> animate cursor and highlight items
24804
+ let shouldNotifyBeatChange = false;
24805
+ if (this._playerState === PlayerState.Playing && !stop) {
24806
+ if (this.settings.player.enableElementHighlighting && beatsToHighlight) {
24807
+ for (let highlight of beatsToHighlight) {
24808
+ let className = BeatContainerGlyph.getGroupId(highlight);
24809
+ this.uiFacade.highlightElements(className, beat.voice.bar.index);
24810
+ }
24811
+ }
24812
+ if (this.settings.player.enableAnimatedBeatCursor) {
24813
+ let nextBeatX = barBoundings.visualBounds.x + barBoundings.visualBounds.w;
24814
+ // get position of next beat on same stavegroup
24815
+ if (nextBeat) {
24816
+ // if we are moving within the same bar or to the next bar
24817
+ // transition to the next beat, otherwise transition to the end of the bar.
24818
+ if ((nextBeat.voice.bar.index === beat.voice.bar.index && nextBeat.index > beat.index) ||
24819
+ nextBeat.voice.bar.index === beat.voice.bar.index + 1) {
24820
+ let nextBeatBoundings = cache.findBeat(nextBeat);
24821
+ if (nextBeatBoundings &&
24822
+ nextBeatBoundings.barBounds.masterBarBounds.staveGroupBounds ===
24823
+ barBoundings.staveGroupBounds) {
24824
+ nextBeatX = nextBeatBoundings.visualBounds.x;
24655
24825
  }
24656
24826
  }
24657
24827
  }
24828
+ // we need to put the transition to an own animation frame
24829
+ // otherwise the stop animation above is not applied.
24830
+ this.uiFacade.beginInvoke(() => {
24831
+ beatCursor.transitionToX(duration / this.playbackSpeed, nextBeatX);
24832
+ });
24658
24833
  }
24659
- // trigger an event for others to indicate which beat/bar is played
24834
+ shouldScroll = !stop;
24835
+ shouldNotifyBeatChange = true;
24836
+ }
24837
+ if (shouldScroll && !this._beatMouseDown && this.settings.player.scrollMode !== exports.ScrollMode.Off) {
24838
+ this.internalScrollToCursor(barBoundings);
24839
+ }
24840
+ // trigger an event for others to indicate which beat/bar is played
24841
+ if (shouldNotifyBeatChange) {
24660
24842
  this.onPlayedBeatChanged(beat);
24661
24843
  }
24662
24844
  }
@@ -24963,8 +25145,10 @@
24963
25145
  if (this._isDestroyed) {
24964
25146
  return;
24965
25147
  }
24966
- this.playerPositionChanged.trigger(e);
24967
- this.uiFacade.triggerEvent(this.container, 'playerPositionChanged', e);
25148
+ if (this.score !== null && this.tracks.length > 0) {
25149
+ this.playerPositionChanged.trigger(e);
25150
+ this.uiFacade.triggerEvent(this.container, 'playerPositionChanged', e);
25151
+ }
24968
25152
  }
24969
25153
  onMidiEventsPlayed(e) {
24970
25154
  if (this._isDestroyed) {
@@ -25970,6 +26154,7 @@
25970
26154
  this.boundsLookup = null;
25971
26155
  this.preRender = new EventEmitterOfT();
25972
26156
  this.partialRenderFinished = new EventEmitterOfT();
26157
+ this.partialLayoutFinished = new EventEmitterOfT();
25973
26158
  this.renderFinished = new EventEmitterOfT();
25974
26159
  this.postRenderFinished = new EventEmitter();
25975
26160
  this.error = new EventEmitterOfT();
@@ -26022,6 +26207,12 @@
26022
26207
  cmd: 'alphaTab.resizeRender'
26023
26208
  });
26024
26209
  }
26210
+ renderResult(resultId) {
26211
+ this._worker.postMessage({
26212
+ cmd: 'alphaTab.renderResult',
26213
+ resultId: resultId
26214
+ });
26215
+ }
26025
26216
  get width() {
26026
26217
  return this._width;
26027
26218
  }
@@ -26042,6 +26233,9 @@
26042
26233
  case 'alphaTab.partialRenderFinished':
26043
26234
  this.partialRenderFinished.trigger(data.result);
26044
26235
  break;
26236
+ case 'alphaTab.partialLayoutFinished':
26237
+ this.partialLayoutFinished.trigger(data.result);
26238
+ break;
26045
26239
  case 'alphaTab.renderFinished':
26046
26240
  this.renderFinished.trigger(data.result);
26047
26241
  break;
@@ -26055,7 +26249,7 @@
26055
26249
  }
26056
26250
  }
26057
26251
  renderScore(score, trackIndexes) {
26058
- let jsObject = JsonConverter.scoreToJsObject(score);
26252
+ let jsObject = score == null ? null : JsonConverter.scoreToJsObject(score);
26059
26253
  this._worker.postMessage({
26060
26254
  cmd: 'alphaTab.renderScore',
26061
26255
  score: jsObject,
@@ -26255,6 +26449,16 @@
26255
26449
  }
26256
26450
  }
26257
26451
 
26452
+ /**
26453
+ * @target web
26454
+ */
26455
+ var ResultState;
26456
+ (function (ResultState) {
26457
+ ResultState[ResultState["LayoutDone"] = 0] = "LayoutDone";
26458
+ ResultState[ResultState["RenderRequested"] = 1] = "RenderRequested";
26459
+ ResultState[ResultState["RenderDone"] = 2] = "RenderDone";
26460
+ ResultState[ResultState["Detached"] = 3] = "Detached";
26461
+ })(ResultState || (ResultState = {}));
26258
26462
  /**
26259
26463
  * @target web
26260
26464
  */
@@ -26266,12 +26470,12 @@
26266
26470
  this._totalResultCount = 0;
26267
26471
  this._initialTrackIndexes = null;
26268
26472
  this._barToElementLookup = new Map();
26473
+ this._resultIdToElementLookup = new Map();
26269
26474
  this.rootContainerBecameVisible = new EventEmitter();
26270
26475
  this.canRenderChanged = new EventEmitter();
26271
26476
  this._highlightedElements = [];
26272
26477
  this._scrollContainer = null;
26273
- if (Environment.webPlatform !== WebPlatform.Browser &&
26274
- Environment.webPlatform !== WebPlatform.BrowserModule) {
26478
+ if (Environment.webPlatform !== WebPlatform.Browser && Environment.webPlatform !== WebPlatform.BrowserModule) {
26275
26479
  throw new AlphaTabError(exports.AlphaTabErrorType.General, 'Usage of AlphaTabApi is only possible in browser environments. For usage in node use the Low Level APIs');
26276
26480
  }
26277
26481
  rootElement.classList.add('alphaTab');
@@ -26314,15 +26518,34 @@
26314
26518
  }
26315
26519
  onElementVisibilityChanged(entries) {
26316
26520
  for (const e of entries) {
26317
- if (e.isIntersecting) {
26318
- const htmlElement = e.target;
26319
- if (htmlElement === this.rootContainer.element) {
26521
+ const htmlElement = e.target;
26522
+ if (htmlElement === this.rootContainer.element) {
26523
+ if (e.isIntersecting) {
26320
26524
  this.rootContainerBecameVisible.trigger();
26321
26525
  this._intersectionObserver.unobserve(this.rootContainer.element);
26322
26526
  }
26323
- else if ('svg' in htmlElement.dataset) {
26324
- this.replacePlaceholder(htmlElement, htmlElement.dataset['svg']);
26325
- this._intersectionObserver.unobserve(htmlElement);
26527
+ }
26528
+ else if ('layoutResultId' in htmlElement && this._api.settings.core.enableLazyLoading) {
26529
+ const placeholder = htmlElement;
26530
+ if (e.isIntersecting) {
26531
+ // missing result or result not matching layout -> request render
26532
+ if (placeholder.renderedResultId !== placeholder.layoutResultId) {
26533
+ if (this._resultIdToElementLookup.has(placeholder.layoutResultId)) {
26534
+ this._api.renderer.renderResult(placeholder.layoutResultId);
26535
+ }
26536
+ else {
26537
+ htmlElement.replaceChildren();
26538
+ }
26539
+ }
26540
+ // detached and became visible
26541
+ else if (placeholder.resultState === ResultState.Detached) {
26542
+ htmlElement.replaceChildren(...placeholder.renderedResult);
26543
+ placeholder.resultState = ResultState.RenderDone;
26544
+ }
26545
+ }
26546
+ else if (placeholder.resultState === ResultState.RenderDone) {
26547
+ placeholder.resultState = ResultState.Detached;
26548
+ placeholder.replaceChildren();
26326
26549
  }
26327
26550
  }
26328
26551
  }
@@ -26386,6 +26609,7 @@
26386
26609
  canvasElement.style.fontSize = '0';
26387
26610
  canvasElement.style.overflow = 'hidden';
26388
26611
  canvasElement.style.lineHeight = '0';
26612
+ canvasElement.style.position = 'relative';
26389
26613
  return new HtmlElementContainer(canvasElement);
26390
26614
  }
26391
26615
  triggerEvent(container, name, details = null, originalEvent) {
@@ -26451,6 +26675,7 @@
26451
26675
  initialRender() {
26452
26676
  this._api.renderer.preRender.on((_) => {
26453
26677
  this._totalResultCount = 0;
26678
+ this._resultIdToElementLookup.clear();
26454
26679
  this._barToElementLookup.clear();
26455
26680
  });
26456
26681
  const initialRender = () => {
@@ -26573,57 +26798,68 @@
26573
26798
  }
26574
26799
  return dataAttributes;
26575
26800
  }
26801
+ beginUpdateRenderResults(renderResult) {
26802
+ if (!this._resultIdToElementLookup.has(renderResult.id)) {
26803
+ return;
26804
+ }
26805
+ const placeholder = this._resultIdToElementLookup.get(renderResult.id);
26806
+ const body = renderResult.renderResult;
26807
+ if (typeof body === 'string') {
26808
+ placeholder.innerHTML = body;
26809
+ }
26810
+ else if ('nodeType' in body) {
26811
+ placeholder.replaceChildren(body);
26812
+ }
26813
+ placeholder.resultState = ResultState.RenderDone;
26814
+ placeholder.renderedResultId = renderResult.id;
26815
+ placeholder.renderedResult = Array.from(placeholder.children);
26816
+ }
26576
26817
  beginAppendRenderResults(renderResult) {
26577
- let canvasElement = this._api.canvasElement.element;
26818
+ const canvasElement = this._api.canvasElement.element;
26578
26819
  // null result indicates that the rendering finished
26579
26820
  if (!renderResult) {
26580
26821
  // so we remove elements that might be from a previous render session
26581
26822
  while (canvasElement.childElementCount > this._totalResultCount) {
26823
+ if (this._api.settings.core.enableLazyLoading) {
26824
+ this._intersectionObserver.unobserve(canvasElement.lastChild);
26825
+ }
26582
26826
  canvasElement.removeChild(canvasElement.lastChild);
26583
26827
  }
26584
26828
  }
26585
26829
  else {
26586
- let body = renderResult.renderResult;
26587
- if (typeof body === 'string') {
26588
- let placeholder;
26589
- if (this._totalResultCount < canvasElement.childElementCount) {
26590
- placeholder = canvasElement.childNodes.item(this._totalResultCount);
26591
- }
26592
- else {
26593
- placeholder = document.createElement('div');
26594
- canvasElement.appendChild(placeholder);
26595
- }
26596
- placeholder.style.width = renderResult.width + 'px';
26597
- placeholder.style.height = renderResult.height + 'px';
26598
- placeholder.style.display = 'inline-block';
26599
- if (!this._api.settings.core.enableLazyLoading) {
26600
- this.replacePlaceholder(placeholder, body);
26601
- }
26602
- else {
26603
- placeholder.dataset['svg'] = body;
26604
- this._intersectionObserver.observe(placeholder);
26605
- }
26606
- // remember which bar is contained in which node for faster lookup
26607
- // on highlight/unhighlight
26608
- for (let i = renderResult.firstMasterBarIndex; i <= renderResult.lastMasterBarIndex; i++) {
26609
- this._barToElementLookup.set(i, placeholder);
26610
- }
26830
+ let placeholder;
26831
+ if (this._totalResultCount < canvasElement.childElementCount) {
26832
+ placeholder = canvasElement.childNodes.item(this._totalResultCount);
26611
26833
  }
26612
26834
  else {
26613
- if (this._totalResultCount < canvasElement.childElementCount) {
26614
- canvasElement.replaceChild(renderResult.renderResult, canvasElement.childNodes.item(this._totalResultCount));
26615
- }
26616
- else {
26617
- canvasElement.appendChild(renderResult.renderResult);
26618
- }
26835
+ placeholder = document.createElement('div');
26836
+ canvasElement.appendChild(placeholder);
26837
+ }
26838
+ placeholder.style.zIndex = '1';
26839
+ placeholder.style.position = 'absolute';
26840
+ placeholder.style.left = renderResult.x + 'px';
26841
+ placeholder.style.top = renderResult.y + 'px';
26842
+ placeholder.style.width = renderResult.width + 'px';
26843
+ placeholder.style.height = renderResult.height + 'px';
26844
+ placeholder.style.display = 'inline-block';
26845
+ placeholder.layoutResultId = renderResult.id;
26846
+ placeholder.resultState = ResultState.LayoutDone;
26847
+ delete placeholder.renderedResultId;
26848
+ delete placeholder.renderedResult;
26849
+ this._resultIdToElementLookup.set(renderResult.id, placeholder);
26850
+ // remember which bar is contained in which node for faster lookup
26851
+ // on highlight/unhighlight
26852
+ for (let i = renderResult.firstMasterBarIndex; i <= renderResult.lastMasterBarIndex; i++) {
26853
+ this._barToElementLookup.set(i, placeholder);
26854
+ }
26855
+ if (this._api.settings.core.enableLazyLoading) {
26856
+ // re-observe to fire event
26857
+ this._intersectionObserver.unobserve(placeholder);
26858
+ this._intersectionObserver.observe(placeholder);
26619
26859
  }
26620
26860
  this._totalResultCount++;
26621
26861
  }
26622
26862
  }
26623
- replacePlaceholder(placeholder, body) {
26624
- placeholder.innerHTML = body;
26625
- delete placeholder.dataset['svg'];
26626
- }
26627
26863
  /**
26628
26864
  * This method creates the player. It detects browser compatibility and
26629
26865
  * initializes a alphaSynth version for the client.
@@ -28851,7 +29087,7 @@
28851
29087
  this.getVoiceContainer(g.beat.voice).addGlyph(g);
28852
29088
  }
28853
29089
  getVoiceContainer(voice) {
28854
- return this._voiceContainers.get(voice.index);
29090
+ return this._voiceContainers.has(voice.index) ? this._voiceContainers.get(voice.index) : undefined;
28855
29091
  }
28856
29092
  getBeatContainer(beat) {
28857
29093
  var _a, _b;
@@ -31836,7 +32072,6 @@
31836
32072
  this.paintPartial(cx + this.x, cy + this.y, canvas, 0, this.masterBarsRenderers.length);
31837
32073
  }
31838
32074
  paintPartial(cx, cy, canvas, startIndex, count) {
31839
- this.buildBoundingsLookup(cx, cy);
31840
32075
  for (let i = 0, j = this._allStaves.length; i < j; i++) {
31841
32076
  this._allStaves[i].paint(cx, cy, canvas, startIndex, count);
31842
32077
  }
@@ -32087,8 +32322,14 @@
32087
32322
  }
32088
32323
  }
32089
32324
 
32325
+ class LazyPartial {
32326
+ constructor(args, renderCallback) {
32327
+ this.args = args;
32328
+ this.renderCallback = renderCallback;
32329
+ }
32330
+ }
32090
32331
  /**
32091
- * This is the base public class for creating new layouting engines for the score renderer.
32332
+ * This is the base class for creating new layouting engines for the score renderer.
32092
32333
  */
32093
32334
  class ScoreLayout {
32094
32335
  constructor(renderer) {
@@ -32098,11 +32339,17 @@
32098
32339
  this.scoreInfoGlyphs = new Map();
32099
32340
  this.chordDiagrams = null;
32100
32341
  this.tuningGlyph = null;
32342
+ this._lazyPartials = new Map();
32101
32343
  this.firstBarIndex = 0;
32102
32344
  this.lastBarIndex = 0;
32103
32345
  this.renderer = renderer;
32104
32346
  }
32347
+ resize() {
32348
+ this._lazyPartials.clear();
32349
+ this.doResize();
32350
+ }
32105
32351
  layoutAndRender() {
32352
+ this._lazyPartials.clear();
32106
32353
  let score = this.renderer.score;
32107
32354
  let startIndex = this.renderer.settings.display.startBar;
32108
32355
  startIndex--; // map to array index
@@ -32118,6 +32365,28 @@
32118
32365
  this.createScoreInfoGlyphs();
32119
32366
  this.doLayoutAndRender();
32120
32367
  }
32368
+ registerPartial(args, callback) {
32369
+ this.renderer.partialLayoutFinished.trigger(args);
32370
+ if (!this.renderer.settings.core.enableLazyLoading) {
32371
+ this.internalRenderLazyPartial(args, callback);
32372
+ }
32373
+ else {
32374
+ this._lazyPartials.set(args.id, new LazyPartial(args, callback));
32375
+ }
32376
+ }
32377
+ internalRenderLazyPartial(args, callback) {
32378
+ const canvas = this.renderer.canvas;
32379
+ canvas.beginRender(args.width, args.height);
32380
+ callback(canvas);
32381
+ args.renderResult = canvas.endRender();
32382
+ this.renderer.partialRenderFinished.trigger(args);
32383
+ }
32384
+ renderLazyPartial(resultId) {
32385
+ if (this._lazyPartials.has(resultId)) {
32386
+ const lazyPartial = this._lazyPartials.get(resultId);
32387
+ this.internalRenderLazyPartial(lazyPartial.args, lazyPartial.renderCallback);
32388
+ }
32389
+ }
32121
32390
  createScoreInfoGlyphs() {
32122
32391
  Logger.debug('ScoreLayout', 'Creating score info glyphs');
32123
32392
  let notation = this.renderer.settings.notation;
@@ -32176,11 +32445,14 @@
32176
32445
  let chords = new Map();
32177
32446
  for (let track of this.renderer.tracks) {
32178
32447
  for (let staff of track.staves) {
32179
- for (const [chordId, chord] of staff.chords) {
32180
- if (!chords.has(chordId)) {
32181
- if (chord.showDiagram) {
32182
- chords.set(chordId, chord);
32183
- this.chordDiagrams.addChord(chord);
32448
+ const sc = staff.chords;
32449
+ if (sc) {
32450
+ for (const [chordId, chord] of sc) {
32451
+ if (!chords.has(chordId)) {
32452
+ if (chord.showDiagram) {
32453
+ chords.set(chordId, chord);
32454
+ this.chordDiagrams.addChord(chord);
32455
+ }
32184
32456
  }
32185
32457
  }
32186
32458
  }
@@ -32254,35 +32526,39 @@
32254
32526
  }
32255
32527
  return null;
32256
32528
  }
32257
- renderAnnotation() {
32529
+ layoutAndRenderAnnotation(y) {
32258
32530
  // attention, you are not allowed to remove change this notice within any version of this library without permission!
32259
32531
  let msg = 'rendered by alphaTab';
32260
- let canvas = this.renderer.canvas;
32261
32532
  let resources = this.renderer.settings.display.resources;
32262
32533
  let size = 12 * this.renderer.settings.display.scale;
32263
- let height = size * 2;
32264
- this.height += height;
32265
- let x = this.width / 2;
32266
- canvas.beginRender(this.width, height);
32267
- canvas.color = resources.mainGlyphColor;
32268
- canvas.font = new Font(resources.copyrightFont.family, size, FontStyle.Plain, FontWeight.Bold);
32269
- canvas.textAlign = TextAlign.Center;
32270
- canvas.fillText(msg, x, size);
32271
- let result = canvas.endRender();
32272
- let e = new RenderFinishedEventArgs();
32273
- e.width = this.width;
32534
+ let height = Math.floor(size * 2);
32535
+ const e = new RenderFinishedEventArgs();
32536
+ const font = new Font(resources.copyrightFont.family, size, FontStyle.Plain, FontWeight.Bold);
32537
+ this.renderer.canvas.font = font;
32538
+ const centered = Environment.getLayoutEngineFactory(this.renderer.settings.display.layoutMode).vertical;
32539
+ e.width = this.renderer.canvas.measureText(msg);
32274
32540
  e.height = height;
32275
- e.renderResult = result;
32541
+ e.x = centered
32542
+ ? (this.width - e.width) / 2
32543
+ : this.firstBarX;
32544
+ e.y = y;
32276
32545
  e.totalWidth = this.width;
32277
- e.totalHeight = this.height;
32546
+ e.totalHeight = y + height;
32278
32547
  e.firstMasterBarIndex = -1;
32279
32548
  e.lastMasterBarIndex = -1;
32280
- this.renderer.partialRenderFinished.trigger(e);
32549
+ this.registerPartial(e, canvas => {
32550
+ canvas.color = resources.mainGlyphColor;
32551
+ canvas.font = font;
32552
+ canvas.textAlign = TextAlign.Left;
32553
+ canvas.fillText(msg, 0, size);
32554
+ });
32555
+ return y + height;
32281
32556
  }
32282
32557
  }
32283
32558
 
32284
32559
  class HorizontalScreenLayoutPartialInfo {
32285
32560
  constructor() {
32561
+ this.x = 0;
32286
32562
  this.width = 0;
32287
32563
  this.masterBars = [];
32288
32564
  }
@@ -32302,7 +32578,16 @@
32302
32578
  get supportsResize() {
32303
32579
  return false;
32304
32580
  }
32305
- resize() { }
32581
+ get firstBarX() {
32582
+ let x = this._pagePadding[0];
32583
+ if (this._group) {
32584
+ x += this._group.accoladeSpacing;
32585
+ }
32586
+ return x;
32587
+ }
32588
+ doResize() {
32589
+ // not supported
32590
+ }
32306
32591
  doLayoutAndRender() {
32307
32592
  this._pagePadding = this.renderer.settings.display.padding;
32308
32593
  if (!this._pagePadding) {
@@ -32325,7 +32610,6 @@
32325
32610
  ];
32326
32611
  }
32327
32612
  let score = this.renderer.score;
32328
- let canvas = this.renderer.canvas;
32329
32613
  let startIndex = this.renderer.settings.display.startBar;
32330
32614
  startIndex--; // map to array index
32331
32615
  startIndex = Math.min(score.masterBars.length - 1, Math.max(0, startIndex));
@@ -32343,6 +32627,7 @@
32343
32627
  let countPerPartial = this.renderer.settings.display.barCountPerPartial;
32344
32628
  let partials = [];
32345
32629
  let currentPartial = new HorizontalScreenLayoutPartialInfo();
32630
+ let renderX = 0;
32346
32631
  while (currentBarIndex <= endBarIndex) {
32347
32632
  let result = this._group.addBars(this.renderer.tracks, currentBarIndex);
32348
32633
  if (result) {
@@ -32352,6 +32637,8 @@
32352
32637
  let previousPartial = partials[partials.length - 1];
32353
32638
  previousPartial.masterBars.push(score.masterBars[currentBarIndex]);
32354
32639
  previousPartial.width += result.width;
32640
+ renderX += result.width;
32641
+ currentPartial.x += renderX;
32355
32642
  }
32356
32643
  else {
32357
32644
  currentPartial.masterBars.push(score.masterBars[currentBarIndex]);
@@ -32359,14 +32646,17 @@
32359
32646
  // no targetPartial here because previous partials already handled this code
32360
32647
  if (currentPartial.masterBars.length >= countPerPartial) {
32361
32648
  if (partials.length === 0) {
32362
- currentPartial.width += this._group.x + this._group.accoladeSpacing;
32649
+ // respect accolade and on first partial
32650
+ currentPartial.width += this._group.accoladeSpacing + this._pagePadding[0];
32363
32651
  }
32652
+ renderX += currentPartial.width;
32364
32653
  partials.push(currentPartial);
32365
32654
  Logger.debug(this.name, 'Finished partial from bar ' +
32366
32655
  currentPartial.masterBars[0].index +
32367
32656
  ' to ' +
32368
32657
  currentPartial.masterBars[currentPartial.masterBars.length - 1].index, null);
32369
32658
  currentPartial = new HorizontalScreenLayoutPartialInfo();
32659
+ currentPartial.x = renderX;
32370
32660
  }
32371
32661
  }
32372
32662
  }
@@ -32375,7 +32665,7 @@
32375
32665
  // don't miss the last partial if not empty
32376
32666
  if (currentPartial.masterBars.length > 0) {
32377
32667
  if (partials.length === 0) {
32378
- currentPartial.width += this._group.x + this._group.accoladeSpacing;
32668
+ currentPartial.width += this._group.accoladeSpacing + this._pagePadding[0];
32379
32669
  }
32380
32670
  partials.push(currentPartial);
32381
32671
  Logger.debug(this.name, 'Finished partial from bar ' +
@@ -32384,35 +32674,44 @@
32384
32674
  currentPartial.masterBars[currentPartial.masterBars.length - 1].index, null);
32385
32675
  }
32386
32676
  this._group.finalizeGroup();
32387
- this.height = this._group.y + this._group.height + this._pagePadding[3];
32677
+ this.height = Math.floor(this._group.y + this._group.height);
32388
32678
  this.width = this._group.x + this._group.width + this._pagePadding[2];
32389
32679
  currentBarIndex = 0;
32680
+ let x = 0;
32390
32681
  for (let i = 0; i < partials.length; i++) {
32391
- let partial = partials[i];
32392
- canvas.beginRender(partial.width, this.height);
32393
- canvas.color = this.renderer.settings.display.resources.mainGlyphColor;
32394
- canvas.textAlign = TextAlign.Left;
32395
- let renderX = this._group.getBarX(partial.masterBars[0].index) + this._group.accoladeSpacing;
32396
- if (i === 0) {
32397
- renderX -= this._group.x + this._group.accoladeSpacing;
32398
- }
32399
- Logger.debug(this.name, 'Rendering partial from bar ' +
32400
- partial.masterBars[0].index +
32401
- ' to ' +
32402
- partial.masterBars[partial.masterBars.length - 1].index, null);
32403
- this._group.paintPartial(-renderX, this._group.y, this.renderer.canvas, currentBarIndex, partial.masterBars.length);
32404
- let result = canvas.endRender();
32405
- let e = new RenderFinishedEventArgs();
32682
+ const partial = partials[i];
32683
+ const e = new RenderFinishedEventArgs();
32684
+ e.x = x;
32685
+ e.y = 0;
32406
32686
  e.totalWidth = this.width;
32407
32687
  e.totalHeight = this.height;
32408
32688
  e.width = partial.width;
32409
32689
  e.height = this.height;
32410
- e.renderResult = result;
32411
32690
  e.firstMasterBarIndex = partial.masterBars[0].index;
32412
32691
  e.lastMasterBarIndex = partial.masterBars[partial.masterBars.length - 1].index;
32413
- this.renderer.partialRenderFinished.trigger(e);
32692
+ x += partial.width;
32693
+ // pull to local scope for lambda
32694
+ const partialBarIndex = currentBarIndex;
32695
+ const partialIndex = i;
32696
+ this._group.buildBoundingsLookup(this._group.x, this._group.y);
32697
+ this.registerPartial(e, canvas => {
32698
+ canvas.color = this.renderer.settings.display.resources.mainGlyphColor;
32699
+ canvas.textAlign = TextAlign.Left;
32700
+ let renderX = this._group.getBarX(partial.masterBars[0].index) + this._group.accoladeSpacing;
32701
+ if (partialIndex === 0) {
32702
+ renderX -= this._group.x + this._group.accoladeSpacing;
32703
+ }
32704
+ canvas.color = this.renderer.settings.display.resources.mainGlyphColor;
32705
+ canvas.textAlign = TextAlign.Left;
32706
+ Logger.debug(this.name, 'Rendering partial from bar ' +
32707
+ partial.masterBars[0].index +
32708
+ ' to ' +
32709
+ partial.masterBars[partial.masterBars.length - 1].index, null);
32710
+ this._group.paintPartial(-renderX, this._group.y, canvas, partialBarIndex, partial.masterBars.length);
32711
+ });
32414
32712
  currentBarIndex += partial.masterBars.length;
32415
32713
  }
32714
+ this.height = this.layoutAndRenderAnnotation(this.height) + this._pagePadding[3];
32416
32715
  }
32417
32716
  }
32418
32717
  HorizontalScreenLayout.PagePadding = [20, 20, 20, 20];
@@ -32453,13 +32752,12 @@
32453
32752
  this._pagePadding[1]
32454
32753
  ];
32455
32754
  }
32456
- let x = this._pagePadding[0];
32457
- let y = this._pagePadding[1];
32755
+ let y = 0;
32458
32756
  this.width = this.renderer.width;
32459
32757
  this._allMasterBarRenderers = [];
32460
32758
  //
32461
32759
  // 1. Score Info
32462
- y = this.layoutAndRenderScoreInfo(x, y, -1);
32760
+ y = this.layoutAndRenderScoreInfo(y, -1);
32463
32761
  //
32464
32762
  // 2. Tunings
32465
32763
  y = this.layoutAndRenderTunings(y, -1);
@@ -32468,20 +32766,27 @@
32468
32766
  y = this.layoutAndRenderChordDiagrams(y, -1);
32469
32767
  //
32470
32768
  // 4. One result per StaveGroup
32471
- y = this.layoutAndRenderScore(x, y);
32769
+ y = this.layoutAndRenderScore(y);
32770
+ y = this.layoutAndRenderAnnotation(y);
32472
32771
  this.height = y + this._pagePadding[3];
32473
32772
  }
32474
32773
  get supportsResize() {
32475
32774
  return true;
32476
32775
  }
32477
- resize() {
32776
+ get firstBarX() {
32478
32777
  let x = this._pagePadding[0];
32479
- let y = this._pagePadding[1];
32778
+ if (this._groups.length > 0) {
32779
+ x += this._groups[0].accoladeSpacing;
32780
+ }
32781
+ return x;
32782
+ }
32783
+ doResize() {
32784
+ let y = 0;
32480
32785
  this.width = this.renderer.width;
32481
32786
  let oldHeight = this.height;
32482
32787
  //
32483
32788
  // 1. Score Info
32484
- y = this.layoutAndRenderScoreInfo(x, y, oldHeight);
32789
+ y = this.layoutAndRenderScoreInfo(y, oldHeight);
32485
32790
  //
32486
32791
  // 2. Tunings
32487
32792
  y = this.layoutAndRenderTunings(y, oldHeight);
@@ -32490,7 +32795,8 @@
32490
32795
  y = this.layoutAndRenderChordDiagrams(y, oldHeight);
32491
32796
  //
32492
32797
  // 4. One result per StaveGroup
32493
- y = this.resizeAndRenderScore(x, y, oldHeight);
32798
+ y = this.resizeAndRenderScore(y, oldHeight);
32799
+ y = this.layoutAndRenderAnnotation(y);
32494
32800
  this.height = y + this._pagePadding[3];
32495
32801
  }
32496
32802
  layoutAndRenderTunings(y, totalHeight = -1) {
@@ -32498,54 +32804,56 @@
32498
32804
  return y;
32499
32805
  }
32500
32806
  let res = this.renderer.settings.display.resources;
32807
+ this.tuningGlyph.x = this._pagePadding[0];
32501
32808
  this.tuningGlyph.width = this.width;
32502
32809
  this.tuningGlyph.doLayout();
32503
32810
  let tuningHeight = this.tuningGlyph.height + 11 * this.scale;
32504
- y += tuningHeight;
32505
- let canvas = this.renderer.canvas;
32506
- canvas.beginRender(this.width, tuningHeight);
32507
- canvas.color = res.scoreInfoColor;
32508
- canvas.textAlign = TextAlign.Center;
32509
- this.tuningGlyph.paint(this._pagePadding[0], 0, canvas);
32510
- let result = canvas.endRender();
32511
- let e = new RenderFinishedEventArgs();
32811
+ const e = new RenderFinishedEventArgs();
32812
+ e.x = 0;
32813
+ e.y = y;
32512
32814
  e.width = this.width;
32513
32815
  e.height = tuningHeight;
32514
- e.renderResult = result;
32515
32816
  e.totalWidth = this.width;
32516
- e.totalHeight = totalHeight < 0 ? y : totalHeight;
32817
+ e.totalHeight = totalHeight < 0 ? y + e.height : totalHeight;
32517
32818
  e.firstMasterBarIndex = -1;
32518
32819
  e.lastMasterBarIndex = -1;
32519
- this.renderer.partialRenderFinished.trigger(e);
32520
- return y;
32820
+ this.registerPartial(e, (canvas) => {
32821
+ canvas.color = res.scoreInfoColor;
32822
+ canvas.textAlign = TextAlign.Center;
32823
+ this.tuningGlyph.paint(0, 0, canvas);
32824
+ });
32825
+ return y + tuningHeight;
32521
32826
  }
32522
32827
  layoutAndRenderChordDiagrams(y, totalHeight = -1) {
32523
32828
  if (!this.chordDiagrams) {
32524
32829
  return y;
32525
32830
  }
32526
- let res = this.renderer.settings.display.resources;
32831
+ const res = this.renderer.settings.display.resources;
32527
32832
  this.chordDiagrams.width = this.width;
32528
32833
  this.chordDiagrams.doLayout();
32529
- let canvas = this.renderer.canvas;
32530
- canvas.beginRender(this.width, this.chordDiagrams.height);
32531
- canvas.color = res.scoreInfoColor;
32532
- canvas.textAlign = TextAlign.Center;
32533
- this.chordDiagrams.paint(0, 0, canvas);
32534
- let result = canvas.endRender();
32535
- y += this.chordDiagrams.height;
32536
- let e = new RenderFinishedEventArgs();
32834
+ const diagramHeight = Math.floor(this.chordDiagrams.height);
32835
+ const e = new RenderFinishedEventArgs();
32836
+ e.x = 0;
32837
+ e.y = y;
32537
32838
  e.width = this.width;
32538
- e.height = this.chordDiagrams.height;
32539
- e.renderResult = result;
32839
+ e.height = diagramHeight;
32540
32840
  e.totalWidth = this.width;
32541
- e.totalHeight = totalHeight < 0 ? y : totalHeight;
32841
+ e.totalHeight = totalHeight < 0 ? y + diagramHeight : totalHeight;
32542
32842
  e.firstMasterBarIndex = -1;
32543
32843
  e.lastMasterBarIndex = -1;
32544
- this.renderer.partialRenderFinished.trigger(e);
32545
- return y;
32844
+ this.registerPartial(e, (canvas) => {
32845
+ canvas.color = res.scoreInfoColor;
32846
+ canvas.textAlign = TextAlign.Center;
32847
+ this.chordDiagrams.paint(0, 0, canvas);
32848
+ });
32849
+ return y + diagramHeight;
32546
32850
  }
32547
- layoutAndRenderScoreInfo(x, y, totalHeight = -1) {
32851
+ layoutAndRenderScoreInfo(y, totalHeight = -1) {
32548
32852
  Logger.debug(this.name, 'Layouting score info');
32853
+ const e = new RenderFinishedEventArgs();
32854
+ e.x = 0;
32855
+ e.y = y;
32856
+ let infoHeight = this._pagePadding[1];
32549
32857
  let scale = this.scale;
32550
32858
  let res = this.renderer.settings.display.resources;
32551
32859
  let centeredGlyphs = [
@@ -32559,9 +32867,9 @@
32559
32867
  if (this.scoreInfoGlyphs.has(centeredGlyphs[i])) {
32560
32868
  let glyph = this.scoreInfoGlyphs.get(centeredGlyphs[i]);
32561
32869
  glyph.x = this.width / 2;
32562
- glyph.y = y;
32870
+ glyph.y = infoHeight;
32563
32871
  glyph.textAlign = TextAlign.Center;
32564
- y += glyph.font.size * scale;
32872
+ infoHeight += glyph.font.size * scale;
32565
32873
  }
32566
32874
  }
32567
32875
  let musicOrWords = false;
@@ -32569,51 +32877,46 @@
32569
32877
  if (this.scoreInfoGlyphs.has(NotationElement.ScoreMusic)) {
32570
32878
  let glyph = this.scoreInfoGlyphs.get(NotationElement.ScoreMusic);
32571
32879
  glyph.x = this.width - this._pagePadding[2];
32572
- glyph.y = y;
32880
+ glyph.y = infoHeight;
32573
32881
  glyph.textAlign = TextAlign.Right;
32574
32882
  musicOrWords = true;
32575
32883
  musicOrWordsHeight = glyph.font.size * scale;
32576
32884
  }
32577
32885
  if (this.scoreInfoGlyphs.has(NotationElement.ScoreWords)) {
32578
32886
  let glyph = this.scoreInfoGlyphs.get(NotationElement.ScoreWords);
32579
- glyph.x = x;
32580
- glyph.y = y;
32887
+ glyph.x = this._pagePadding[0];
32888
+ glyph.y = infoHeight;
32581
32889
  glyph.textAlign = TextAlign.Left;
32582
32890
  musicOrWords = true;
32583
32891
  musicOrWordsHeight = glyph.font.size * scale;
32584
32892
  }
32585
32893
  if (musicOrWords) {
32586
- y += musicOrWordsHeight;
32894
+ infoHeight += musicOrWordsHeight;
32587
32895
  }
32588
- y += 17 * this.scale;
32589
- let canvas = this.renderer.canvas;
32590
- canvas.beginRender(this.width, y);
32591
- canvas.color = res.scoreInfoColor;
32592
- canvas.textAlign = TextAlign.Center;
32593
- for (const g of this.scoreInfoGlyphs.values()) {
32594
- g.paint(0, 0, canvas);
32595
- }
32596
- let result = canvas.endRender();
32597
- let e = new RenderFinishedEventArgs();
32896
+ infoHeight = Math.floor(infoHeight + 17 * this.scale);
32598
32897
  e.width = this.width;
32599
- e.height = y;
32600
- e.renderResult = result;
32898
+ e.height = infoHeight;
32601
32899
  e.totalWidth = this.width;
32602
- e.totalHeight = totalHeight < 0 ? y : totalHeight;
32900
+ e.totalHeight = totalHeight < 0 ? y + e.height : totalHeight;
32603
32901
  e.firstMasterBarIndex = -1;
32604
32902
  e.lastMasterBarIndex = -1;
32605
- this.renderer.partialRenderFinished.trigger(e);
32606
- return y;
32903
+ this.registerPartial(e, (canvas) => {
32904
+ canvas.color = res.scoreInfoColor;
32905
+ canvas.textAlign = TextAlign.Center;
32906
+ for (const g of this.scoreInfoGlyphs.values()) {
32907
+ g.paint(0, 0, canvas);
32908
+ }
32909
+ });
32910
+ return y + infoHeight;
32607
32911
  }
32608
- resizeAndRenderScore(x, y, oldHeight) {
32609
- let canvas = this.renderer.canvas;
32912
+ resizeAndRenderScore(y, oldHeight) {
32610
32913
  // if we have a fixed number of bars per row, we only need to refit them.
32611
32914
  if (this.renderer.settings.display.barsPerRow !== -1) {
32612
32915
  for (let i = 0; i < this._groups.length; i++) {
32613
32916
  let group = this._groups[i];
32614
32917
  this.fitGroup(group);
32615
32918
  group.finalizeGroup();
32616
- y += this.paintGroup(group, oldHeight, canvas);
32919
+ y += this.paintGroup(group, oldHeight);
32617
32920
  }
32618
32921
  }
32619
32922
  else {
@@ -32622,7 +32925,7 @@
32622
32925
  let maxWidth = this.maxWidth;
32623
32926
  let group = this.createEmptyStaveGroup();
32624
32927
  group.index = this._groups.length;
32625
- group.x = x;
32928
+ group.x = this._pagePadding[0];
32626
32929
  group.y = y;
32627
32930
  while (currentIndex < this._allMasterBarRenderers.length) {
32628
32931
  // if the current renderer still has space in the current group add it
@@ -32646,11 +32949,11 @@
32646
32949
  this._groups.push(group);
32647
32950
  this.fitGroup(group);
32648
32951
  group.finalizeGroup();
32649
- y += this.paintGroup(group, oldHeight, canvas);
32952
+ y += this.paintGroup(group, oldHeight);
32650
32953
  // note: we do not increase currentIndex here to have it added to the next group
32651
32954
  group = this.createEmptyStaveGroup();
32652
32955
  group.index = this._groups.length;
32653
- group.x = x;
32956
+ group.x = this._pagePadding[0];
32654
32957
  group.y = y;
32655
32958
  }
32656
32959
  }
@@ -32658,12 +32961,11 @@
32658
32961
  // don't forget to finish the last group
32659
32962
  this.fitGroup(group);
32660
32963
  group.finalizeGroup();
32661
- y += this.paintGroup(group, oldHeight, canvas);
32964
+ y += this.paintGroup(group, oldHeight);
32662
32965
  }
32663
32966
  return y;
32664
32967
  }
32665
- layoutAndRenderScore(x, y) {
32666
- let canvas = this.renderer.canvas;
32968
+ layoutAndRenderScore(y) {
32667
32969
  let startIndex = this.firstBarIndex;
32668
32970
  let currentBarIndex = startIndex;
32669
32971
  let endBarIndex = this.lastBarIndex;
@@ -32672,38 +32974,39 @@
32672
32974
  // create group and align set proper coordinates
32673
32975
  let group = this.createStaveGroup(currentBarIndex, endBarIndex);
32674
32976
  this._groups.push(group);
32675
- group.x = x;
32977
+ group.x = this._pagePadding[0];
32676
32978
  group.y = y;
32677
32979
  currentBarIndex = group.lastBarIndex + 1;
32678
32980
  // finalize group (sizing etc).
32679
32981
  this.fitGroup(group);
32680
32982
  group.finalizeGroup();
32681
32983
  Logger.debug(this.name, 'Rendering partial from bar ' + group.firstBarIndex + ' to ' + group.lastBarIndex, null);
32682
- y += this.paintGroup(group, y, canvas);
32984
+ y += this.paintGroup(group, y);
32683
32985
  }
32684
32986
  return y;
32685
32987
  }
32686
- paintGroup(group, totalHeight, canvas) {
32988
+ paintGroup(group, totalHeight) {
32687
32989
  // paint into canvas
32688
- let height = group.height + 20 * this.scale;
32689
- canvas.beginRender(this.width, height);
32690
- this.renderer.canvas.color = this.renderer.settings.display.resources.mainGlyphColor;
32691
- this.renderer.canvas.textAlign = TextAlign.Left;
32692
- // NOTE: we use this negation trick to make the group paint itself to 0/0 coordinates
32693
- // since we use partial drawing
32694
- group.paint(0, -group.y, canvas);
32695
- // calculate coordinates for next group
32696
- totalHeight += height;
32697
- let result = canvas.endRender();
32698
- let args = new RenderFinishedEventArgs();
32990
+ let height = Math.floor(group.height + 20 * this.scale);
32991
+ const args = new RenderFinishedEventArgs();
32992
+ args.x = 0;
32993
+ args.y = group.y;
32699
32994
  args.totalWidth = this.width;
32700
32995
  args.totalHeight = totalHeight;
32701
32996
  args.width = this.width;
32702
32997
  args.height = height;
32703
- args.renderResult = result;
32704
32998
  args.firstMasterBarIndex = group.firstBarIndex;
32705
32999
  args.lastMasterBarIndex = group.lastBarIndex;
32706
- this.renderer.partialRenderFinished.trigger(args);
33000
+ group.buildBoundingsLookup(0, 0);
33001
+ this.registerPartial(args, canvas => {
33002
+ this.renderer.canvas.color = this.renderer.settings.display.resources.mainGlyphColor;
33003
+ this.renderer.canvas.textAlign = TextAlign.Left;
33004
+ // NOTE: we use this negation trick to make the group paint itself to 0/0 coordinates
33005
+ // since we use partial drawing
33006
+ group.paint(0, -args.y, canvas);
33007
+ });
33008
+ // calculate coordinates for next group
33009
+ totalHeight += height;
32707
33010
  return height;
32708
33011
  }
32709
33012
  /**
@@ -32713,7 +33016,6 @@
32713
33016
  if (group.isFull || group.width > this.maxWidth) {
32714
33017
  group.scaleToWidth(this.maxWidth);
32715
33018
  }
32716
- this.width = Math.max(this.width, group.width);
32717
33019
  }
32718
33020
  createStaveGroup(currentBarIndex, endIndex) {
32719
33021
  let group = this.createEmptyStaveGroup();
@@ -39146,7 +39448,7 @@
39146
39448
  }
39147
39449
  else if (c.attributes.has('end') && this._tieStarts.length > 0 && !note.isTieDestination) {
39148
39450
  note.isTieDestination = true;
39149
- note.tieOriginNoteId = this._tieStarts[0].id;
39451
+ note.tieOrigin = this._tieStarts[0];
39150
39452
  this._tieStarts.splice(0, 1);
39151
39453
  this._tieStartIds.delete(note.id);
39152
39454
  }
@@ -40292,8 +40594,8 @@
40292
40594
  // </auto-generated>
40293
40595
  class VersionInfo {
40294
40596
  }
40295
- VersionInfo.version = '1.3.0-alpha.138';
40296
- VersionInfo.date = '2021-12-29T15:54:57.422Z';
40597
+ VersionInfo.version = '1.3.0-alpha.142';
40598
+ VersionInfo.date = '2022-01-15T17:24:56.552Z';
40297
40599
 
40298
40600
  var index$5 = /*#__PURE__*/Object.freeze({
40299
40601
  __proto__: null,
@@ -41185,95 +41487,98 @@
41185
41487
  const diagramCollectionProperty = properties.addElement('Property');
41186
41488
  diagramCollectionProperty.attributes.set('name', name);
41187
41489
  const diagramCollectionItems = diagramCollectionProperty.addElement('Items');
41188
- for (const [id, chord] of staff.chords) {
41189
- const diagramCollectionItem = diagramCollectionItems.addElement('Item');
41190
- diagramCollectionItem.attributes.set('id', id);
41191
- diagramCollectionItem.attributes.set('name', chord.name);
41192
- const diagram = diagramCollectionItem.addElement('Diagram');
41193
- diagram.attributes.set('stringCount', chord.strings.length.toString());
41194
- diagram.attributes.set('fretCount', '5');
41195
- diagram.attributes.set('baseFret', (chord.firstFret - 1).toString());
41196
- diagram.attributes.set('barStates', chord.strings.map(_ => '1').join(' '));
41197
- const frets = [];
41198
- const fretToStrings = new Map();
41199
- for (let i = 0; i < chord.strings.length; i++) {
41200
- let chordFret = chord.strings[i];
41201
- if (chordFret !== -1) {
41202
- const fretNode = diagram.addElement('Fret');
41203
- const chordString = (chord.strings.length - 1 - i);
41204
- fretNode.attributes.set('string', chordString.toString());
41205
- fretNode.attributes.set('fret', (chordFret - chord.firstFret + 1).toString());
41206
- if (!fretToStrings.has(chordFret)) {
41207
- fretToStrings.set(chordFret, []);
41208
- frets.push(chordFret);
41209
- }
41210
- fretToStrings.get(chordFret).push(chordString);
41211
- }
41212
- }
41213
- frets.sort();
41214
- // try to rebuild the barre frets
41215
- const fingering = diagram.addElement('Fingering');
41216
- if (chord.barreFrets.length > 0) {
41217
- const fingers = [
41218
- Fingers.LittleFinger,
41219
- Fingers.AnnularFinger,
41220
- Fingers.MiddleFinger,
41221
- Fingers.IndexFinger,
41222
- ];
41223
- for (const fret of frets) {
41224
- const fretStrings = fretToStrings.get(fret);
41225
- if (fretStrings.length > 1 && chord.barreFrets.indexOf(fret) >= 0) {
41226
- const finger = fingers.length > 0 ? fingers.pop() : Fingers.IndexFinger;
41227
- for (const fretString of fretStrings) {
41228
- const position = fingering.addElement('Position');
41229
- switch (finger) {
41230
- case Fingers.LittleFinger:
41231
- position.attributes.set('finger', 'Pinky');
41232
- break;
41233
- case Fingers.AnnularFinger:
41234
- position.attributes.set('finger', 'Ring');
41235
- break;
41236
- case Fingers.MiddleFinger:
41237
- position.attributes.set('finger', 'Middle');
41238
- break;
41239
- case Fingers.IndexFinger:
41240
- position.attributes.set('finger', 'Index');
41241
- break;
41490
+ const sc = staff.chords;
41491
+ if (sc) {
41492
+ for (const [id, chord] of sc) {
41493
+ const diagramCollectionItem = diagramCollectionItems.addElement('Item');
41494
+ diagramCollectionItem.attributes.set('id', id);
41495
+ diagramCollectionItem.attributes.set('name', chord.name);
41496
+ const diagram = diagramCollectionItem.addElement('Diagram');
41497
+ diagram.attributes.set('stringCount', chord.strings.length.toString());
41498
+ diagram.attributes.set('fretCount', '5');
41499
+ diagram.attributes.set('baseFret', (chord.firstFret - 1).toString());
41500
+ diagram.attributes.set('barStates', chord.strings.map(_ => '1').join(' '));
41501
+ const frets = [];
41502
+ const fretToStrings = new Map();
41503
+ for (let i = 0; i < chord.strings.length; i++) {
41504
+ let chordFret = chord.strings[i];
41505
+ if (chordFret !== -1) {
41506
+ const fretNode = diagram.addElement('Fret');
41507
+ const chordString = (chord.strings.length - 1 - i);
41508
+ fretNode.attributes.set('string', chordString.toString());
41509
+ fretNode.attributes.set('fret', (chordFret - chord.firstFret + 1).toString());
41510
+ if (!fretToStrings.has(chordFret)) {
41511
+ fretToStrings.set(chordFret, []);
41512
+ frets.push(chordFret);
41513
+ }
41514
+ fretToStrings.get(chordFret).push(chordString);
41515
+ }
41516
+ }
41517
+ frets.sort();
41518
+ // try to rebuild the barre frets
41519
+ const fingering = diagram.addElement('Fingering');
41520
+ if (chord.barreFrets.length > 0) {
41521
+ const fingers = [
41522
+ Fingers.LittleFinger,
41523
+ Fingers.AnnularFinger,
41524
+ Fingers.MiddleFinger,
41525
+ Fingers.IndexFinger,
41526
+ ];
41527
+ for (const fret of frets) {
41528
+ const fretStrings = fretToStrings.get(fret);
41529
+ if (fretStrings.length > 1 && chord.barreFrets.indexOf(fret) >= 0) {
41530
+ const finger = fingers.length > 0 ? fingers.pop() : Fingers.IndexFinger;
41531
+ for (const fretString of fretStrings) {
41532
+ const position = fingering.addElement('Position');
41533
+ switch (finger) {
41534
+ case Fingers.LittleFinger:
41535
+ position.attributes.set('finger', 'Pinky');
41536
+ break;
41537
+ case Fingers.AnnularFinger:
41538
+ position.attributes.set('finger', 'Ring');
41539
+ break;
41540
+ case Fingers.MiddleFinger:
41541
+ position.attributes.set('finger', 'Middle');
41542
+ break;
41543
+ case Fingers.IndexFinger:
41544
+ position.attributes.set('finger', 'Index');
41545
+ break;
41546
+ }
41547
+ position.attributes.set('fret', (fret - chord.firstFret + 1).toString());
41548
+ position.attributes.set('string', fretString.toString());
41242
41549
  }
41243
- position.attributes.set('fret', (fret - chord.firstFret + 1).toString());
41244
- position.attributes.set('string', fretString.toString());
41245
41550
  }
41246
41551
  }
41247
41552
  }
41553
+ const showName = diagram.addElement('Property');
41554
+ showName.attributes.set('name', 'ShowName');
41555
+ showName.attributes.set('type', 'bool');
41556
+ showName.attributes.set('value', chord.showName ? "true" : "false");
41557
+ const showDiagram = diagram.addElement('Property');
41558
+ showDiagram.attributes.set('name', 'ShowDiagram');
41559
+ showDiagram.attributes.set('type', 'bool');
41560
+ showDiagram.attributes.set('value', chord.showDiagram ? "true" : "false");
41561
+ const showFingering = diagram.addElement('Property');
41562
+ showFingering.attributes.set('name', 'ShowFingering');
41563
+ showFingering.attributes.set('type', 'bool');
41564
+ showFingering.attributes.set('value', chord.showFingering ? "true" : "false");
41565
+ // TODO Chord details
41566
+ const chordNode = diagram.addElement('Chord');
41567
+ const keyNoteNode = chordNode.addElement('KeyNote');
41568
+ keyNoteNode.attributes.set('step', 'C');
41569
+ keyNoteNode.attributes.set('accidental', 'Natural');
41570
+ const bassNoteNode = chordNode.addElement('BassNote');
41571
+ bassNoteNode.attributes.set('step', 'C');
41572
+ bassNoteNode.attributes.set('accidental', 'Natural');
41573
+ const degree1Node = chordNode.addElement('Degree');
41574
+ degree1Node.attributes.set('interval', 'Third');
41575
+ degree1Node.attributes.set('alteration', 'Major');
41576
+ degree1Node.attributes.set('omitted', 'false');
41577
+ const degree2Node = chordNode.addElement('Degree');
41578
+ degree2Node.attributes.set('interval', 'Fifth');
41579
+ degree2Node.attributes.set('alteration', 'Perfect');
41580
+ degree2Node.attributes.set('omitted', 'false');
41248
41581
  }
41249
- const showName = diagram.addElement('Property');
41250
- showName.attributes.set('name', 'ShowName');
41251
- showName.attributes.set('type', 'bool');
41252
- showName.attributes.set('value', chord.showName ? "true" : "false");
41253
- const showDiagram = diagram.addElement('Property');
41254
- showDiagram.attributes.set('name', 'ShowDiagram');
41255
- showDiagram.attributes.set('type', 'bool');
41256
- showDiagram.attributes.set('value', chord.showDiagram ? "true" : "false");
41257
- const showFingering = diagram.addElement('Property');
41258
- showFingering.attributes.set('name', 'ShowFingering');
41259
- showFingering.attributes.set('type', 'bool');
41260
- showFingering.attributes.set('value', chord.showFingering ? "true" : "false");
41261
- // TODO Chord details
41262
- const chordNode = diagram.addElement('Chord');
41263
- const keyNoteNode = chordNode.addElement('KeyNote');
41264
- keyNoteNode.attributes.set('step', 'C');
41265
- keyNoteNode.attributes.set('accidental', 'Natural');
41266
- const bassNoteNode = chordNode.addElement('BassNote');
41267
- bassNoteNode.attributes.set('step', 'C');
41268
- bassNoteNode.attributes.set('accidental', 'Natural');
41269
- const degree1Node = chordNode.addElement('Degree');
41270
- degree1Node.attributes.set('interval', 'Third');
41271
- degree1Node.attributes.set('alteration', 'Major');
41272
- degree1Node.attributes.set('omitted', 'false');
41273
- const degree2Node = chordNode.addElement('Degree');
41274
- degree2Node.attributes.set('interval', 'Fifth');
41275
- degree2Node.attributes.set('alteration', 'Perfect');
41276
- degree2Node.attributes.set('omitted', 'false');
41277
41582
  }
41278
41583
  }
41279
41584
  writeSimplePropertyNode(parent, propertyName, propertyValueTagName, propertyValue) {
@@ -41476,10 +41781,12 @@
41476
41781
  this.writeFermatas(masterBarNode, masterBar);
41477
41782
  }
41478
41783
  writeFermatas(parent, masterBar) {
41479
- if (masterBar.fermata.size === 0) {
41784
+ var _a, _b;
41785
+ const fermataCount = ((_b = (_a = masterBar.fermata) === null || _a === void 0 ? void 0 : _a.size) !== null && _b !== void 0 ? _b : 0);
41786
+ if (fermataCount === 0) {
41480
41787
  return;
41481
41788
  }
41482
- if (masterBar.fermata.size > 0) {
41789
+ if (fermataCount > 0) {
41483
41790
  const fermatas = parent.addElement('Fermatas');
41484
41791
  for (const [offset, fermata] of masterBar.fermata) {
41485
41792
  this.writeFermata(fermatas, offset, fermata);