@coderline/alphatab 1.6.0-alpha.1409 → 1.6.0-alpha.1416

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.
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * alphaTab v1.6.0-alpha.1409 (develop, build 1409)
2
+ * alphaTab v1.6.0-alpha.1416 (develop, build 1416)
3
3
  *
4
4
  * Copyright © 2025, Daniel Kuschny and Contributors, All rights reserved.
5
5
  *
@@ -1413,7 +1413,7 @@ class SyncPointData {
1413
1413
  this.barOccurence = 0;
1414
1414
  /**
1415
1415
  * The modified tempo at which the cursor should move (aka. the tempo played within the external audio track).
1416
- * This information is used together with the {@link originalTempo} to calculate how much faster/slower the
1416
+ * This information is used together with normal tempo changes to calculate how much faster/slower the
1417
1417
  * cursor playback is performed to align with the audio track.
1418
1418
  */
1419
1419
  this.modifiedTempo = 0;
@@ -3371,18 +3371,26 @@ class ModelUtils {
3371
3371
  const lookup = new Map();
3372
3372
  const score = tracks[0].score;
3373
3373
  let currentIndex = startIndex;
3374
+ let tempo = score.tempo;
3374
3375
  while (currentIndex <= endIndexInclusive) {
3375
3376
  const currentGroupStartIndex = currentIndex;
3376
3377
  let currentGroup = null;
3377
3378
  while (currentIndex <= endIndexInclusive) {
3378
3379
  const masterBar = score.masterBars[currentIndex];
3380
+ let hasTempoChange = false;
3381
+ for (const a of masterBar.tempoAutomations) {
3382
+ if (a.value !== tempo) {
3383
+ hasTempoChange = true;
3384
+ }
3385
+ tempo = a.value;
3386
+ }
3379
3387
  // check if masterbar breaks multibar rests, it must be fully empty with no annotations
3380
3388
  if (masterBar.alternateEndings ||
3381
3389
  (masterBar.isRepeatStart && masterBar.index !== currentGroupStartIndex) ||
3382
3390
  masterBar.isFreeTime ||
3383
3391
  masterBar.isAnacrusis ||
3384
3392
  masterBar.section !== null ||
3385
- (masterBar.index !== currentGroupStartIndex && masterBar.tempoAutomations.length > 0) ||
3393
+ (masterBar.index !== currentGroupStartIndex && hasTempoChange) ||
3386
3394
  (masterBar.fermata !== null && masterBar.fermata.size > 0) ||
3387
3395
  (masterBar.directions !== null && masterBar.directions.size > 0)) {
3388
3396
  break;
@@ -20215,7 +20223,11 @@ class MusicXmlImporter extends ScoreImporter {
20215
20223
  for (const c of element.childElements()) {
20216
20224
  switch (c.localName) {
20217
20225
  case 'direction-type':
20218
- directionTypes.push(c.firstElement);
20226
+ // See https://github.com/CoderLine/alphaTab/issues/2102
20227
+ const type = c.firstElement;
20228
+ if (type) {
20229
+ directionTypes.push(type);
20230
+ }
20219
20231
  break;
20220
20232
  case 'offset':
20221
20233
  offset = Number.parseFloat(c.innerText);
@@ -38596,6 +38608,93 @@ class AlphaSynthWrapper {
38596
38608
  }
38597
38609
  }
38598
38610
 
38611
+ /**
38612
+ * A {@link IScoreRenderer} implementation wrapping and underling other {@link IScoreRenderer}
38613
+ * allowing dynamic changing of the underlying instance without loosing aspects like the
38614
+ * event listeners.
38615
+ */
38616
+ class ScoreRendererWrapper {
38617
+ constructor() {
38618
+ this._width = 0;
38619
+ this._score = null;
38620
+ this._trackIndexes = null;
38621
+ this.preRender = new EventEmitterOfT();
38622
+ this.renderFinished = new EventEmitterOfT();
38623
+ this.partialRenderFinished = new EventEmitterOfT();
38624
+ this.partialLayoutFinished = new EventEmitterOfT();
38625
+ this.postRenderFinished = new EventEmitter();
38626
+ this.error = new EventEmitterOfT();
38627
+ }
38628
+ get instance() {
38629
+ return this._instance;
38630
+ }
38631
+ set instance(value) {
38632
+ this._instance = value;
38633
+ // unregister all events from previous instance
38634
+ const unregister = this._instanceEventUnregister;
38635
+ if (unregister) {
38636
+ for (const e of unregister) {
38637
+ e();
38638
+ }
38639
+ }
38640
+ if (value) {
38641
+ // regsiter to events of new player and forward them to existing listeners
38642
+ const newUnregister = [];
38643
+ newUnregister.push(value.preRender.on(v => this.preRender.trigger(v)));
38644
+ newUnregister.push(value.renderFinished.on(v => this.renderFinished.trigger(v)));
38645
+ newUnregister.push(value.partialRenderFinished.on(v => this.partialRenderFinished.trigger(v)));
38646
+ newUnregister.push(value.partialLayoutFinished.on(v => this.partialLayoutFinished.trigger(v)));
38647
+ newUnregister.push(value.postRenderFinished.on(() => this.postRenderFinished.trigger()));
38648
+ newUnregister.push(value.error.on(v => this.error.trigger(v)));
38649
+ this._instanceEventUnregister = newUnregister;
38650
+ if (this._settings) {
38651
+ value.updateSettings(this._settings);
38652
+ }
38653
+ value.width = this._width;
38654
+ if (this._score !== null) {
38655
+ value.renderScore(this._score, this._trackIndexes);
38656
+ }
38657
+ }
38658
+ else {
38659
+ this._instanceEventUnregister = undefined;
38660
+ }
38661
+ }
38662
+ get boundsLookup() {
38663
+ return this._instance ? this._instance.boundsLookup : null;
38664
+ }
38665
+ get width() {
38666
+ return this._instance ? this._instance.width : 0;
38667
+ }
38668
+ set width(value) {
38669
+ this._width = value;
38670
+ if (this._instance) {
38671
+ this._instance.width = value;
38672
+ }
38673
+ }
38674
+ render() {
38675
+ this._instance?.render();
38676
+ }
38677
+ resizeRender() {
38678
+ this._instance?.resizeRender();
38679
+ }
38680
+ renderScore(score, trackIndexes) {
38681
+ this._score = score;
38682
+ this._trackIndexes = trackIndexes;
38683
+ this._instance?.renderScore(score, trackIndexes);
38684
+ }
38685
+ renderResult(resultId) {
38686
+ this._instance?.renderResult(resultId);
38687
+ }
38688
+ updateSettings(settings) {
38689
+ this._settings = settings;
38690
+ this._instance?.updateSettings(settings);
38691
+ }
38692
+ destroy() {
38693
+ this._instance?.destroy();
38694
+ this._instance = undefined;
38695
+ }
38696
+ }
38697
+
38599
38698
  class SelectionInfo {
38600
38699
  constructor(beat) {
38601
38700
  this.bounds = null;
@@ -38610,11 +38709,27 @@ class SelectionInfo {
38610
38709
  */
38611
38710
  class AlphaTabApiBase {
38612
38711
  /**
38613
- * The actual player mode which is currently active (e.g. allows determining whether a backing track or the synthesizer is active).
38712
+ * The actual player mode which is currently active.
38713
+ * @remarks
38714
+ * Allows determining whether a backing track or the synthesizer is active in case automatic detection is enabled.
38715
+ * @category Properties - Player
38716
+ * @since 1.6.0
38614
38717
  */
38615
38718
  get actualPlayerMode() {
38616
38719
  return this._actualPlayerMode;
38617
38720
  }
38721
+ /**
38722
+ * The score renderer used for rendering the music sheet.
38723
+ * @remarks
38724
+ * This is the low-level API responsible for the actual rendering engine.
38725
+ * Gets access to the underling {@link IScoreRenderer} that is used for the rendering.
38726
+ *
38727
+ * @category Properties - Core
38728
+ * @since 0.9.4
38729
+ */
38730
+ get renderer() {
38731
+ return this._renderer;
38732
+ }
38618
38733
  /**
38619
38734
  * The score holding all information about the song being rendered
38620
38735
  * @category Properties - Core
@@ -38693,6 +38808,7 @@ class AlphaTabApiBase {
38693
38808
  this._previousTick = 0;
38694
38809
  this._currentBeat = null;
38695
38810
  this._currentBeatBounds = null;
38811
+ this._isInitialBeatCursorUpdate = true;
38696
38812
  this._previousStateForCursor = PlayerState.Paused;
38697
38813
  this._previousCursorCache = null;
38698
38814
  this._lastScroll = 0;
@@ -39351,7 +39467,40 @@ class AlphaTabApiBase {
39351
39467
  */
39352
39468
  this.midiLoaded = new EventEmitterOfT();
39353
39469
  /**
39354
- * @internal
39470
+ * This event is fired when a settings update was requested.
39471
+ *
39472
+ * @eventProperty
39473
+ * @category Events - Core
39474
+ * @since 1.6.0
39475
+ *
39476
+ * @example
39477
+ * JavaScript
39478
+ * ```js
39479
+ * const api = new alphaTab.AlphaTabApi(document.querySelector('#alphaTab'));
39480
+ * api.settingsUpdated.on(() => {
39481
+ * updateSettingsUI(api.settings);
39482
+ * });
39483
+ * ```
39484
+ *
39485
+ * @example
39486
+ * C#
39487
+ * ```cs
39488
+ * var api = new AlphaTabApi<MyControl>(...);
39489
+ * api.SettingsUpdated.On(() =>
39490
+ * {
39491
+ * UpdateSettingsUI(api.settings);
39492
+ * });
39493
+ * ```
39494
+ *
39495
+ * @example
39496
+ * Android
39497
+ * ```kotlin
39498
+ * val api = AlphaTabApi<MyControl>(...)
39499
+ * api.SettingsUpdated.on {
39500
+ * updateSettingsUI(api.settings)
39501
+ * }
39502
+ * ```
39503
+ *
39355
39504
  */
39356
39505
  this.settingsUpdated = new EventEmitter();
39357
39506
  this.uiFacade = uiFacade;
@@ -39365,46 +39514,46 @@ class AlphaTabApiBase {
39365
39514
  Environment.printEnvironmentInfo(false);
39366
39515
  this.canvasElement = uiFacade.createCanvasElement();
39367
39516
  this.container.appendChild(this.canvasElement);
39517
+ this._renderer = new ScoreRendererWrapper();
39368
39518
  if (this.settings.core.useWorkers &&
39369
39519
  this.uiFacade.areWorkersSupported &&
39370
39520
  Environment.getRenderEngineFactory(this.settings.core.engine).supportsWorkers) {
39371
- this.renderer = this.uiFacade.createWorkerRenderer();
39521
+ this._renderer.instance = this.uiFacade.createWorkerRenderer();
39372
39522
  }
39373
39523
  else {
39374
- this.renderer = new ScoreRenderer(this.settings);
39524
+ this._renderer.instance = new ScoreRenderer(this.settings);
39375
39525
  }
39376
39526
  this.container.resize.on(Environment.throttle(() => {
39377
39527
  if (this._isDestroyed) {
39378
39528
  return;
39379
39529
  }
39380
- if (this.container.width !== this.renderer.width) {
39530
+ if (this.container.width !== this._renderer.width) {
39381
39531
  this.triggerResize();
39382
39532
  }
39383
39533
  }, uiFacade.resizeThrottle));
39384
39534
  const initialResizeEventInfo = new ResizeEventArgs();
39385
- initialResizeEventInfo.oldWidth = this.renderer.width;
39535
+ initialResizeEventInfo.oldWidth = this._renderer.width;
39386
39536
  initialResizeEventInfo.newWidth = this.container.width | 0;
39387
39537
  initialResizeEventInfo.settings = this.settings;
39388
39538
  this.onResize(initialResizeEventInfo);
39389
- this.renderer.preRender.on(this.onRenderStarted.bind(this));
39390
- this.renderer.renderFinished.on(renderingResult => {
39539
+ this._renderer.preRender.on(this.onRenderStarted.bind(this));
39540
+ this._renderer.renderFinished.on(renderingResult => {
39391
39541
  this.onRenderFinished(renderingResult);
39392
39542
  });
39393
- this.renderer.postRenderFinished.on(() => {
39543
+ this._renderer.postRenderFinished.on(() => {
39394
39544
  const duration = Date.now() - this._startTime;
39395
39545
  Logger.debug('rendering', `Rendering completed in ${duration}ms`);
39396
39546
  this.onPostRenderFinished();
39397
39547
  });
39398
- this.renderer.preRender.on(_ => {
39548
+ this._renderer.preRender.on(_ => {
39399
39549
  this._startTime = Date.now();
39400
39550
  });
39401
- this.renderer.partialLayoutFinished.on(this.appendRenderResult.bind(this));
39402
- this.renderer.partialRenderFinished.on(this.updateRenderResult.bind(this));
39403
- this.renderer.renderFinished.on(r => {
39404
- this.appendRenderResult(r);
39405
- this.appendRenderResult(null); // marks last element
39551
+ this._renderer.partialLayoutFinished.on(r => this.appendRenderResult(r, false));
39552
+ this._renderer.partialRenderFinished.on(this.updateRenderResult.bind(this));
39553
+ this._renderer.renderFinished.on(r => {
39554
+ this.appendRenderResult(r, true);
39406
39555
  });
39407
- this.renderer.error.on(this.onError.bind(this));
39556
+ this._renderer.error.on(this.onError.bind(this));
39408
39557
  this.setupPlayerWrapper();
39409
39558
  if (this.settings.player.playerMode !== PlayerMode.Disabled) {
39410
39559
  this.setupOrDestroyPlayer();
@@ -39479,7 +39628,7 @@ class AlphaTabApiBase {
39479
39628
  this._isDestroyed = true;
39480
39629
  this._player.destroy();
39481
39630
  this.uiFacade.destroy();
39482
- this.renderer.destroy();
39631
+ this._renderer.destroy();
39483
39632
  }
39484
39633
  /**
39485
39634
  * Applies any changes that were done to the settings object.
@@ -39524,12 +39673,30 @@ class AlphaTabApiBase {
39524
39673
  if (score) {
39525
39674
  ModelUtils.applyPitchOffsets(this.settings, score);
39526
39675
  }
39527
- this.renderer.updateSettings(this.settings);
39528
- if (this.setupOrDestroyPlayer()) {
39529
- this.loadMidiForScore();
39530
- }
39676
+ this.updateRenderer();
39677
+ this._renderer.updateSettings(this.settings);
39678
+ this.setupOrDestroyPlayer();
39531
39679
  this.onSettingsUpdated();
39532
39680
  }
39681
+ updateRenderer() {
39682
+ const renderer = this._renderer;
39683
+ if (this.settings.core.useWorkers &&
39684
+ this.uiFacade.areWorkersSupported &&
39685
+ Environment.getRenderEngineFactory(this.settings.core.engine).supportsWorkers) {
39686
+ // switch from non-worker to worker renderer
39687
+ if (renderer.instance instanceof ScoreRenderer) {
39688
+ renderer.destroy();
39689
+ renderer.instance = this.uiFacade.createWorkerRenderer();
39690
+ }
39691
+ }
39692
+ else {
39693
+ // switch from worker to non-worker renderer
39694
+ if (!(renderer.instance instanceof ScoreRenderer)) {
39695
+ renderer.destroy();
39696
+ renderer.instance = new ScoreRenderer(this.settings);
39697
+ }
39698
+ }
39699
+ }
39533
39700
  /**
39534
39701
  * Initiates a load of the score using the given data.
39535
39702
  * @returns true if the data object is supported and a load was initiated, otherwise false
@@ -39724,30 +39891,33 @@ class AlphaTabApiBase {
39724
39891
  }
39725
39892
  else {
39726
39893
  const resizeEventInfo = new ResizeEventArgs();
39727
- resizeEventInfo.oldWidth = this.renderer.width;
39894
+ resizeEventInfo.oldWidth = this._renderer.width;
39728
39895
  resizeEventInfo.newWidth = this.container.width;
39729
39896
  resizeEventInfo.settings = this.settings;
39730
39897
  this.onResize(resizeEventInfo);
39731
- this.renderer.updateSettings(this.settings);
39732
- this.renderer.width = this.container.width;
39733
- this.renderer.resizeRender();
39898
+ this._renderer.updateSettings(this.settings);
39899
+ this._renderer.width = this.container.width;
39900
+ this._renderer.resizeRender();
39734
39901
  }
39735
39902
  }
39736
- appendRenderResult(result) {
39737
- if (result) {
39903
+ appendRenderResult(result, isLast) {
39904
+ // resizing the canvas and wrapper elements at the end is enough
39905
+ // it avoids flickering on resizes and re-renders.
39906
+ // the individual partials are anyhow sized correctly
39907
+ if (isLast) {
39738
39908
  this.canvasElement.width = result.totalWidth;
39739
39909
  this.canvasElement.height = result.totalHeight;
39740
39910
  if (this._cursorWrapper) {
39741
39911
  this._cursorWrapper.width = result.totalWidth;
39742
39912
  this._cursorWrapper.height = result.totalHeight;
39743
39913
  }
39744
- if (result.width > 0 || result.height > 0) {
39745
- this.uiFacade.beginAppendRenderResults(result);
39746
- }
39747
39914
  }
39748
- else {
39915
+ if (result.width > 0 || result.height > 0) {
39749
39916
  this.uiFacade.beginAppendRenderResults(result);
39750
39917
  }
39918
+ if (isLast) {
39919
+ this.uiFacade.beginAppendRenderResults(null);
39920
+ }
39751
39921
  }
39752
39922
  updateRenderResult(result) {
39753
39923
  if (result && result.renderResult) {
@@ -39909,13 +40079,10 @@ class AlphaTabApiBase {
39909
40079
  * ```
39910
40080
  */
39911
40081
  render() {
39912
- if (!this.renderer) {
39913
- return;
39914
- }
39915
40082
  if (this.uiFacade.canRender) {
39916
40083
  // when font is finally loaded, start rendering
39917
- this.renderer.width = this.container.width;
39918
- this.renderer.renderScore(this.score, this._trackIndexes);
40084
+ this._renderer.width = this.container.width;
40085
+ this._renderer.renderScore(this.score, this._trackIndexes);
39919
40086
  }
39920
40087
  else {
39921
40088
  this.uiFacade.canRenderChanged.on(() => this.render());
@@ -39990,7 +40157,7 @@ class AlphaTabApiBase {
39990
40157
  * @since 1.5.0
39991
40158
  */
39992
40159
  get boundsLookup() {
39993
- return this.renderer.boundsLookup;
40160
+ return this._renderer.boundsLookup;
39994
40161
  }
39995
40162
  /**
39996
40163
  * The alphaSynth player used for playback.
@@ -40422,6 +40589,10 @@ class AlphaTabApiBase {
40422
40589
  this._previousTick = 0;
40423
40590
  this.destroyCursors();
40424
40591
  }
40592
+ /**
40593
+ *
40594
+ * @returns true if a new player was created, false if no player was created (includes destroy & reuse of the current one)
40595
+ */
40425
40596
  setupOrDestroyPlayer() {
40426
40597
  let mode = this.settings.player.playerMode;
40427
40598
  if (mode === PlayerMode.EnabledAutomatic) {
@@ -40439,6 +40610,7 @@ class AlphaTabApiBase {
40439
40610
  let newPlayer = null;
40440
40611
  if (mode !== this._actualPlayerMode) {
40441
40612
  this.destroyPlayer();
40613
+ this.updateCursors();
40442
40614
  switch (mode) {
40443
40615
  case PlayerMode.Disabled:
40444
40616
  newPlayer = null;
@@ -40456,9 +40628,9 @@ class AlphaTabApiBase {
40456
40628
  }
40457
40629
  else {
40458
40630
  // no change in player mode, just update song info if needed
40459
- return true;
40631
+ this.updateCursors();
40632
+ return false;
40460
40633
  }
40461
- this.updateCursors();
40462
40634
  this._actualPlayerMode = mode;
40463
40635
  if (!newPlayer) {
40464
40636
  return false;
@@ -40466,6 +40638,13 @@ class AlphaTabApiBase {
40466
40638
  this._player.instance = newPlayer;
40467
40639
  return false;
40468
40640
  }
40641
+ /**
40642
+ * Re-creates the midi for the current score and loads it.
40643
+ * @remarks
40644
+ * This will result in the player to stop playback. Some setting changes require re-genration of the midi song.
40645
+ * @category Methods - Player
40646
+ * @since 1.6.0
40647
+ */
40469
40648
  loadMidiForScore() {
40470
40649
  if (!this.score) {
40471
40650
  return;
@@ -40869,6 +41048,7 @@ class AlphaTabApiBase {
40869
41048
  this._barCursor = cursors.barCursor;
40870
41049
  this._beatCursor = cursors.beatCursor;
40871
41050
  this._selectionWrapper = cursors.selectionWrapper;
41051
+ this._isInitialBeatCursorUpdate = true;
40872
41052
  }
40873
41053
  if (this._currentBeat !== null) {
40874
41054
  this.cursorUpdateBeat(this._currentBeat, false, this._previousTick > 10, 1, true);
@@ -40908,7 +41088,7 @@ class AlphaTabApiBase {
40908
41088
  if (!beat) {
40909
41089
  return;
40910
41090
  }
40911
- const cache = this.renderer.boundsLookup;
41091
+ const cache = this._renderer.boundsLookup;
40912
41092
  if (!cache) {
40913
41093
  return;
40914
41094
  }
@@ -41031,6 +41211,7 @@ class AlphaTabApiBase {
41031
41211
  if (isPlayingUpdate) {
41032
41212
  // we do not "reset" the cursor if we are smoothly moving from left to right.
41033
41213
  const jumpCursor = !previousBeatBounds ||
41214
+ this._isInitialBeatCursorUpdate ||
41034
41215
  barBounds.y !== previousBeatBounds.barBounds.masterBarBounds.visualBounds.y ||
41035
41216
  startBeatX < previousBeatBounds.onNotesX ||
41036
41217
  barBoundings.index > previousBeatBounds.barBounds.masterBarBounds.index + 1;
@@ -41055,13 +41236,16 @@ class AlphaTabApiBase {
41055
41236
  }
41056
41237
  else {
41057
41238
  // ticking cursor
41239
+ beatCursor.transitionToX(0, startBeatX);
41058
41240
  beatCursor.setBounds(startBeatX, barBounds.y, 1, barBounds.h);
41059
41241
  }
41242
+ this._isInitialBeatCursorUpdate = false;
41060
41243
  }
41061
- // if playing, animate the cursor to the next beat
41062
- if (this.settings.player.enableElementHighlighting) {
41063
- this.uiFacade.removeHighlights();
41244
+ else {
41245
+ this._isInitialBeatCursorUpdate = true;
41064
41246
  }
41247
+ // if playing, animate the cursor to the next beat
41248
+ this.uiFacade.removeHighlights();
41065
41249
  // actively playing? -> animate cursor and highlight items
41066
41250
  let shouldNotifyBeatChange = false;
41067
41251
  if (isPlayingUpdate) {
@@ -41225,11 +41409,11 @@ class AlphaTabApiBase {
41225
41409
  }
41226
41410
  const relX = e.getX(this.canvasElement);
41227
41411
  const relY = e.getY(this.canvasElement);
41228
- const beat = this.renderer.boundsLookup?.getBeatAtPos(relX, relY) ?? null;
41412
+ const beat = this._renderer.boundsLookup?.getBeatAtPos(relX, relY) ?? null;
41229
41413
  if (beat) {
41230
41414
  this.onBeatMouseDown(e, beat);
41231
41415
  if (this.settings.core.includeNoteBounds) {
41232
- const note = this.renderer.boundsLookup?.getNoteAtPos(beat, relX, relY);
41416
+ const note = this._renderer.boundsLookup?.getNoteAtPos(beat, relX, relY);
41233
41417
  if (note) {
41234
41418
  this.onNoteMouseDown(e, note);
41235
41419
  }
@@ -41242,11 +41426,11 @@ class AlphaTabApiBase {
41242
41426
  }
41243
41427
  const relX = e.getX(this.canvasElement);
41244
41428
  const relY = e.getY(this.canvasElement);
41245
- const beat = this.renderer.boundsLookup?.getBeatAtPos(relX, relY) ?? null;
41429
+ const beat = this._renderer.boundsLookup?.getBeatAtPos(relX, relY) ?? null;
41246
41430
  if (beat) {
41247
41431
  this.onBeatMouseMove(e, beat);
41248
41432
  if (this._noteMouseDown) {
41249
- const note = this.renderer.boundsLookup?.getNoteAtPos(beat, relX, relY);
41433
+ const note = this._renderer.boundsLookup?.getNoteAtPos(beat, relX, relY);
41250
41434
  if (note) {
41251
41435
  this.onNoteMouseMove(e, note);
41252
41436
  }
@@ -41262,11 +41446,11 @@ class AlphaTabApiBase {
41262
41446
  }
41263
41447
  const relX = e.getX(this.canvasElement);
41264
41448
  const relY = e.getY(this.canvasElement);
41265
- const beat = this.renderer.boundsLookup?.getBeatAtPos(relX, relY) ?? null;
41449
+ const beat = this._renderer.boundsLookup?.getBeatAtPos(relX, relY) ?? null;
41266
41450
  this.onBeatMouseUp(e, beat);
41267
41451
  if (this._noteMouseDown) {
41268
41452
  if (beat) {
41269
- const note = this.renderer.boundsLookup?.getNoteAtPos(beat, relX, relY) ?? null;
41453
+ const note = this._renderer.boundsLookup?.getNoteAtPos(beat, relX, relY) ?? null;
41270
41454
  this.onNoteMouseUp(e, note);
41271
41455
  }
41272
41456
  else {
@@ -41274,7 +41458,7 @@ class AlphaTabApiBase {
41274
41458
  }
41275
41459
  }
41276
41460
  });
41277
- this.renderer.postRenderFinished.on(() => {
41461
+ this._renderer.postRenderFinished.on(() => {
41278
41462
  if (!this._selectionStart ||
41279
41463
  this.settings.player.playerMode === PlayerMode.Disabled ||
41280
41464
  !this.settings.player.enableCursor ||
@@ -41285,7 +41469,7 @@ class AlphaTabApiBase {
41285
41469
  });
41286
41470
  }
41287
41471
  cursorSelectRange(startBeat, endBeat) {
41288
- const cache = this.renderer.boundsLookup;
41472
+ const cache = this._renderer.boundsLookup;
41289
41473
  if (!cache) {
41290
41474
  return;
41291
41475
  }
@@ -41354,7 +41538,8 @@ class AlphaTabApiBase {
41354
41538
  }
41355
41539
  this.scoreLoaded.trigger(score);
41356
41540
  this.uiFacade.triggerEvent(this.container, 'scoreLoaded', score);
41357
- if (this.setupOrDestroyPlayer()) {
41541
+ if (!this.setupOrDestroyPlayer()) {
41542
+ // feed midi into current player (a new player will trigger a midi generation once the player is ready)
41358
41543
  this.loadMidiForScore();
41359
41544
  }
41360
41545
  }
@@ -41384,7 +41569,7 @@ class AlphaTabApiBase {
41384
41569
  return;
41385
41570
  }
41386
41571
  this._currentBeat = null;
41387
- this.cursorUpdateTick(this._previousTick, false, 1, this._previousTick > 10);
41572
+ this.cursorUpdateTick(this._previousTick, false, 1, true, true);
41388
41573
  this.postRenderFinished.trigger();
41389
41574
  this.uiFacade.triggerEvent(this.container, 'postRenderFinished', null);
41390
41575
  }
@@ -46940,7 +47125,7 @@ class StaffSystem {
46940
47125
  return this.masterBarsRenderers[0].masterBar.index;
46941
47126
  }
46942
47127
  get lastBarIndex() {
46943
- return this.masterBarsRenderers[this.masterBarsRenderers.length - 1].masterBar.index;
47128
+ return this.masterBarsRenderers[this.masterBarsRenderers.length - 1].lastMasterBarIndex;
46944
47129
  }
46945
47130
  addMasterBarRenderers(tracks, renderers) {
46946
47131
  if (tracks.length === 0) {
@@ -47754,6 +47939,9 @@ class ScoreLayout {
47754
47939
  }
47755
47940
  }
47756
47941
  }
47942
+ else {
47943
+ this.tuningGlyph = null;
47944
+ }
47757
47945
  }
47758
47946
  // chord diagram glyphs
47759
47947
  if (notation.isNotationElementVisible(NotationElement.ChordDiagrams)) {
@@ -47782,6 +47970,12 @@ class ScoreLayout {
47782
47970
  }
47783
47971
  }
47784
47972
  }
47973
+ if (this.chordDiagrams.isEmpty) {
47974
+ this.chordDiagrams = null;
47975
+ }
47976
+ }
47977
+ else {
47978
+ this.chordDiagrams = null;
47785
47979
  }
47786
47980
  }
47787
47981
  createEmptyStaffSystem() {
@@ -60525,9 +60719,9 @@ class VersionInfo {
60525
60719
  print(`build date: ${VersionInfo.date}`);
60526
60720
  }
60527
60721
  }
60528
- VersionInfo.version = '1.6.0-alpha.1409';
60529
- VersionInfo.date = '2025-05-14T02:06:32.990Z';
60530
- VersionInfo.commit = 'f91fed13b0a0946b3fa9306b480ddf8044b948e2';
60722
+ VersionInfo.version = '1.6.0-alpha.1416';
60723
+ VersionInfo.date = '2025-05-19T16:41:23.634Z';
60724
+ VersionInfo.commit = '4aff072e1be5292482c3d77f434dd1555b6cbb8d';
60531
60725
 
60532
60726
  /**
60533
60727
  * A factory for custom layout engines.
@@ -64841,9 +65035,11 @@ const _barrel = /*#__PURE__*/Object.freeze(/*#__PURE__*/Object.defineProperty({
64841
65035
  ActiveBeatsChangedEventArgs,
64842
65036
  AlphaSynth,
64843
65037
  AlphaSynthAudioWorkletOutput,
65038
+ AlphaSynthBase,
64844
65039
  AlphaSynthScriptProcessorOutput,
64845
65040
  AlphaSynthWebAudioOutputBase,
64846
65041
  AlphaSynthWebWorkerApi,
65042
+ BackingTrackSyncPoint,
64847
65043
  CircularSampleBuffer,
64848
65044
  MidiEventsPlayedEventArgs,
64849
65045
  PlaybackRange,