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

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,5 +1,5 @@
1
1
  /*!
2
- * alphaTab v1.6.0-alpha.1409 (develop, build 1409)
2
+ * alphaTab v1.6.0-alpha.1415 (develop, build 1415)
3
3
  *
4
4
  * Copyright © 2025, Daniel Kuschny and Contributors, All rights reserved.
5
5
  *
@@ -3377,18 +3377,26 @@
3377
3377
  const lookup = new Map();
3378
3378
  const score = tracks[0].score;
3379
3379
  let currentIndex = startIndex;
3380
+ let tempo = score.tempo;
3380
3381
  while (currentIndex <= endIndexInclusive) {
3381
3382
  const currentGroupStartIndex = currentIndex;
3382
3383
  let currentGroup = null;
3383
3384
  while (currentIndex <= endIndexInclusive) {
3384
3385
  const masterBar = score.masterBars[currentIndex];
3386
+ let hasTempoChange = false;
3387
+ for (const a of masterBar.tempoAutomations) {
3388
+ if (a.value !== tempo) {
3389
+ hasTempoChange = true;
3390
+ }
3391
+ tempo = a.value;
3392
+ }
3385
3393
  // check if masterbar breaks multibar rests, it must be fully empty with no annotations
3386
3394
  if (masterBar.alternateEndings ||
3387
3395
  (masterBar.isRepeatStart && masterBar.index !== currentGroupStartIndex) ||
3388
3396
  masterBar.isFreeTime ||
3389
3397
  masterBar.isAnacrusis ||
3390
3398
  masterBar.section !== null ||
3391
- (masterBar.index !== currentGroupStartIndex && masterBar.tempoAutomations.length > 0) ||
3399
+ (masterBar.index !== currentGroupStartIndex && hasTempoChange) ||
3392
3400
  (masterBar.fermata !== null && masterBar.fermata.size > 0) ||
3393
3401
  (masterBar.directions !== null && masterBar.directions.size > 0)) {
3394
3402
  break;
@@ -20221,7 +20229,11 @@
20221
20229
  for (const c of element.childElements()) {
20222
20230
  switch (c.localName) {
20223
20231
  case 'direction-type':
20224
- directionTypes.push(c.firstElement);
20232
+ // See https://github.com/CoderLine/alphaTab/issues/2102
20233
+ const type = c.firstElement;
20234
+ if (type) {
20235
+ directionTypes.push(type);
20236
+ }
20225
20237
  break;
20226
20238
  case 'offset':
20227
20239
  offset = Number.parseFloat(c.innerText);
@@ -38602,6 +38614,93 @@
38602
38614
  }
38603
38615
  }
38604
38616
 
38617
+ /**
38618
+ * A {@link IScoreRenderer} implementation wrapping and underling other {@link IScoreRenderer}
38619
+ * allowing dynamic changing of the underlying instance without loosing aspects like the
38620
+ * event listeners.
38621
+ */
38622
+ class ScoreRendererWrapper {
38623
+ constructor() {
38624
+ this._width = 0;
38625
+ this._score = null;
38626
+ this._trackIndexes = null;
38627
+ this.preRender = new EventEmitterOfT();
38628
+ this.renderFinished = new EventEmitterOfT();
38629
+ this.partialRenderFinished = new EventEmitterOfT();
38630
+ this.partialLayoutFinished = new EventEmitterOfT();
38631
+ this.postRenderFinished = new EventEmitter();
38632
+ this.error = new EventEmitterOfT();
38633
+ }
38634
+ get instance() {
38635
+ return this._instance;
38636
+ }
38637
+ set instance(value) {
38638
+ this._instance = value;
38639
+ // unregister all events from previous instance
38640
+ const unregister = this._instanceEventUnregister;
38641
+ if (unregister) {
38642
+ for (const e of unregister) {
38643
+ e();
38644
+ }
38645
+ }
38646
+ if (value) {
38647
+ // regsiter to events of new player and forward them to existing listeners
38648
+ const newUnregister = [];
38649
+ newUnregister.push(value.preRender.on(v => this.preRender.trigger(v)));
38650
+ newUnregister.push(value.renderFinished.on(v => this.renderFinished.trigger(v)));
38651
+ newUnregister.push(value.partialRenderFinished.on(v => this.partialRenderFinished.trigger(v)));
38652
+ newUnregister.push(value.partialLayoutFinished.on(v => this.partialLayoutFinished.trigger(v)));
38653
+ newUnregister.push(value.postRenderFinished.on(() => this.postRenderFinished.trigger()));
38654
+ newUnregister.push(value.error.on(v => this.error.trigger(v)));
38655
+ this._instanceEventUnregister = newUnregister;
38656
+ if (this._settings) {
38657
+ value.updateSettings(this._settings);
38658
+ }
38659
+ value.width = this._width;
38660
+ if (this._score !== null) {
38661
+ value.renderScore(this._score, this._trackIndexes);
38662
+ }
38663
+ }
38664
+ else {
38665
+ this._instanceEventUnregister = undefined;
38666
+ }
38667
+ }
38668
+ get boundsLookup() {
38669
+ return this._instance ? this._instance.boundsLookup : null;
38670
+ }
38671
+ get width() {
38672
+ return this._instance ? this._instance.width : 0;
38673
+ }
38674
+ set width(value) {
38675
+ this._width = value;
38676
+ if (this._instance) {
38677
+ this._instance.width = value;
38678
+ }
38679
+ }
38680
+ render() {
38681
+ this._instance?.render();
38682
+ }
38683
+ resizeRender() {
38684
+ this._instance?.resizeRender();
38685
+ }
38686
+ renderScore(score, trackIndexes) {
38687
+ this._score = score;
38688
+ this._trackIndexes = trackIndexes;
38689
+ this._instance?.renderScore(score, trackIndexes);
38690
+ }
38691
+ renderResult(resultId) {
38692
+ this._instance?.renderResult(resultId);
38693
+ }
38694
+ updateSettings(settings) {
38695
+ this._settings = settings;
38696
+ this._instance?.updateSettings(settings);
38697
+ }
38698
+ destroy() {
38699
+ this._instance?.destroy();
38700
+ this._instance = undefined;
38701
+ }
38702
+ }
38703
+
38605
38704
  class SelectionInfo {
38606
38705
  constructor(beat) {
38607
38706
  this.bounds = null;
@@ -38621,6 +38720,18 @@
38621
38720
  get actualPlayerMode() {
38622
38721
  return this._actualPlayerMode;
38623
38722
  }
38723
+ /**
38724
+ * The score renderer used for rendering the music sheet.
38725
+ * @remarks
38726
+ * This is the low-level API responsible for the actual rendering engine.
38727
+ * Gets access to the underling {@link IScoreRenderer} that is used for the rendering.
38728
+ *
38729
+ * @category Properties - Core
38730
+ * @since 0.9.4
38731
+ */
38732
+ get renderer() {
38733
+ return this._renderer;
38734
+ }
38624
38735
  /**
38625
38736
  * The score holding all information about the song being rendered
38626
38737
  * @category Properties - Core
@@ -38699,6 +38810,7 @@
38699
38810
  this._previousTick = 0;
38700
38811
  this._currentBeat = null;
38701
38812
  this._currentBeatBounds = null;
38813
+ this._isInitialBeatCursorUpdate = true;
38702
38814
  this._previousStateForCursor = PlayerState.Paused;
38703
38815
  this._previousCursorCache = null;
38704
38816
  this._lastScroll = 0;
@@ -39357,7 +39469,40 @@
39357
39469
  */
39358
39470
  this.midiLoaded = new EventEmitterOfT();
39359
39471
  /**
39360
- * @internal
39472
+ * This event is fired when a settings update was requested.
39473
+ *
39474
+ * @eventProperty
39475
+ * @category Events - Core
39476
+ * @since 1.6.0
39477
+ *
39478
+ * @example
39479
+ * JavaScript
39480
+ * ```js
39481
+ * const api = new alphaTab.AlphaTabApi(document.querySelector('#alphaTab'));
39482
+ * api.settingsUpdated.on(() => {
39483
+ * updateSettingsUI(api.settings);
39484
+ * });
39485
+ * ```
39486
+ *
39487
+ * @example
39488
+ * C#
39489
+ * ```cs
39490
+ * var api = new AlphaTabApi<MyControl>(...);
39491
+ * api.SettingsUpdated.On(() =>
39492
+ * {
39493
+ * UpdateSettingsUI(api.settings);
39494
+ * });
39495
+ * ```
39496
+ *
39497
+ * @example
39498
+ * Android
39499
+ * ```kotlin
39500
+ * val api = AlphaTabApi<MyControl>(...)
39501
+ * api.SettingsUpdated.on {
39502
+ * updateSettingsUI(api.settings)
39503
+ * }
39504
+ * ```
39505
+ *
39361
39506
  */
39362
39507
  this.settingsUpdated = new EventEmitter();
39363
39508
  this.uiFacade = uiFacade;
@@ -39371,46 +39516,46 @@
39371
39516
  Environment.printEnvironmentInfo(false);
39372
39517
  this.canvasElement = uiFacade.createCanvasElement();
39373
39518
  this.container.appendChild(this.canvasElement);
39519
+ this._renderer = new ScoreRendererWrapper();
39374
39520
  if (this.settings.core.useWorkers &&
39375
39521
  this.uiFacade.areWorkersSupported &&
39376
39522
  Environment.getRenderEngineFactory(this.settings.core.engine).supportsWorkers) {
39377
- this.renderer = this.uiFacade.createWorkerRenderer();
39523
+ this._renderer.instance = this.uiFacade.createWorkerRenderer();
39378
39524
  }
39379
39525
  else {
39380
- this.renderer = new ScoreRenderer(this.settings);
39526
+ this._renderer.instance = new ScoreRenderer(this.settings);
39381
39527
  }
39382
39528
  this.container.resize.on(Environment.throttle(() => {
39383
39529
  if (this._isDestroyed) {
39384
39530
  return;
39385
39531
  }
39386
- if (this.container.width !== this.renderer.width) {
39532
+ if (this.container.width !== this._renderer.width) {
39387
39533
  this.triggerResize();
39388
39534
  }
39389
39535
  }, uiFacade.resizeThrottle));
39390
39536
  const initialResizeEventInfo = new ResizeEventArgs();
39391
- initialResizeEventInfo.oldWidth = this.renderer.width;
39537
+ initialResizeEventInfo.oldWidth = this._renderer.width;
39392
39538
  initialResizeEventInfo.newWidth = this.container.width | 0;
39393
39539
  initialResizeEventInfo.settings = this.settings;
39394
39540
  this.onResize(initialResizeEventInfo);
39395
- this.renderer.preRender.on(this.onRenderStarted.bind(this));
39396
- this.renderer.renderFinished.on(renderingResult => {
39541
+ this._renderer.preRender.on(this.onRenderStarted.bind(this));
39542
+ this._renderer.renderFinished.on(renderingResult => {
39397
39543
  this.onRenderFinished(renderingResult);
39398
39544
  });
39399
- this.renderer.postRenderFinished.on(() => {
39545
+ this._renderer.postRenderFinished.on(() => {
39400
39546
  const duration = Date.now() - this._startTime;
39401
39547
  Logger.debug('rendering', `Rendering completed in ${duration}ms`);
39402
39548
  this.onPostRenderFinished();
39403
39549
  });
39404
- this.renderer.preRender.on(_ => {
39550
+ this._renderer.preRender.on(_ => {
39405
39551
  this._startTime = Date.now();
39406
39552
  });
39407
- this.renderer.partialLayoutFinished.on(this.appendRenderResult.bind(this));
39408
- this.renderer.partialRenderFinished.on(this.updateRenderResult.bind(this));
39409
- this.renderer.renderFinished.on(r => {
39410
- this.appendRenderResult(r);
39411
- this.appendRenderResult(null); // marks last element
39553
+ this._renderer.partialLayoutFinished.on(r => this.appendRenderResult(r, false));
39554
+ this._renderer.partialRenderFinished.on(this.updateRenderResult.bind(this));
39555
+ this._renderer.renderFinished.on(r => {
39556
+ this.appendRenderResult(r, true);
39412
39557
  });
39413
- this.renderer.error.on(this.onError.bind(this));
39558
+ this._renderer.error.on(this.onError.bind(this));
39414
39559
  this.setupPlayerWrapper();
39415
39560
  if (this.settings.player.playerMode !== exports.PlayerMode.Disabled) {
39416
39561
  this.setupOrDestroyPlayer();
@@ -39485,7 +39630,7 @@
39485
39630
  this._isDestroyed = true;
39486
39631
  this._player.destroy();
39487
39632
  this.uiFacade.destroy();
39488
- this.renderer.destroy();
39633
+ this._renderer.destroy();
39489
39634
  }
39490
39635
  /**
39491
39636
  * Applies any changes that were done to the settings object.
@@ -39530,12 +39675,30 @@
39530
39675
  if (score) {
39531
39676
  ModelUtils.applyPitchOffsets(this.settings, score);
39532
39677
  }
39533
- this.renderer.updateSettings(this.settings);
39534
- if (this.setupOrDestroyPlayer()) {
39535
- this.loadMidiForScore();
39536
- }
39678
+ this.updateRenderer();
39679
+ this._renderer.updateSettings(this.settings);
39680
+ this.setupOrDestroyPlayer();
39537
39681
  this.onSettingsUpdated();
39538
39682
  }
39683
+ updateRenderer() {
39684
+ const renderer = this._renderer;
39685
+ if (this.settings.core.useWorkers &&
39686
+ this.uiFacade.areWorkersSupported &&
39687
+ Environment.getRenderEngineFactory(this.settings.core.engine).supportsWorkers) {
39688
+ // switch from non-worker to worker renderer
39689
+ if (renderer.instance instanceof ScoreRenderer) {
39690
+ renderer.destroy();
39691
+ renderer.instance = this.uiFacade.createWorkerRenderer();
39692
+ }
39693
+ }
39694
+ else {
39695
+ // switch from worker to non-worker renderer
39696
+ if (!(renderer.instance instanceof ScoreRenderer)) {
39697
+ renderer.destroy();
39698
+ renderer.instance = new ScoreRenderer(this.settings);
39699
+ }
39700
+ }
39701
+ }
39539
39702
  /**
39540
39703
  * Initiates a load of the score using the given data.
39541
39704
  * @returns true if the data object is supported and a load was initiated, otherwise false
@@ -39730,30 +39893,33 @@
39730
39893
  }
39731
39894
  else {
39732
39895
  const resizeEventInfo = new ResizeEventArgs();
39733
- resizeEventInfo.oldWidth = this.renderer.width;
39896
+ resizeEventInfo.oldWidth = this._renderer.width;
39734
39897
  resizeEventInfo.newWidth = this.container.width;
39735
39898
  resizeEventInfo.settings = this.settings;
39736
39899
  this.onResize(resizeEventInfo);
39737
- this.renderer.updateSettings(this.settings);
39738
- this.renderer.width = this.container.width;
39739
- this.renderer.resizeRender();
39900
+ this._renderer.updateSettings(this.settings);
39901
+ this._renderer.width = this.container.width;
39902
+ this._renderer.resizeRender();
39740
39903
  }
39741
39904
  }
39742
- appendRenderResult(result) {
39743
- if (result) {
39905
+ appendRenderResult(result, isLast) {
39906
+ // resizing the canvas and wrapper elements at the end is enough
39907
+ // it avoids flickering on resizes and re-renders.
39908
+ // the individual partials are anyhow sized correctly
39909
+ if (isLast) {
39744
39910
  this.canvasElement.width = result.totalWidth;
39745
39911
  this.canvasElement.height = result.totalHeight;
39746
39912
  if (this._cursorWrapper) {
39747
39913
  this._cursorWrapper.width = result.totalWidth;
39748
39914
  this._cursorWrapper.height = result.totalHeight;
39749
39915
  }
39750
- if (result.width > 0 || result.height > 0) {
39751
- this.uiFacade.beginAppendRenderResults(result);
39752
- }
39753
39916
  }
39754
- else {
39917
+ if (result.width > 0 || result.height > 0) {
39755
39918
  this.uiFacade.beginAppendRenderResults(result);
39756
39919
  }
39920
+ if (isLast) {
39921
+ this.uiFacade.beginAppendRenderResults(null);
39922
+ }
39757
39923
  }
39758
39924
  updateRenderResult(result) {
39759
39925
  if (result && result.renderResult) {
@@ -39915,13 +40081,10 @@
39915
40081
  * ```
39916
40082
  */
39917
40083
  render() {
39918
- if (!this.renderer) {
39919
- return;
39920
- }
39921
40084
  if (this.uiFacade.canRender) {
39922
40085
  // when font is finally loaded, start rendering
39923
- this.renderer.width = this.container.width;
39924
- this.renderer.renderScore(this.score, this._trackIndexes);
40086
+ this._renderer.width = this.container.width;
40087
+ this._renderer.renderScore(this.score, this._trackIndexes);
39925
40088
  }
39926
40089
  else {
39927
40090
  this.uiFacade.canRenderChanged.on(() => this.render());
@@ -39996,7 +40159,7 @@
39996
40159
  * @since 1.5.0
39997
40160
  */
39998
40161
  get boundsLookup() {
39999
- return this.renderer.boundsLookup;
40162
+ return this._renderer.boundsLookup;
40000
40163
  }
40001
40164
  /**
40002
40165
  * The alphaSynth player used for playback.
@@ -40428,6 +40591,10 @@
40428
40591
  this._previousTick = 0;
40429
40592
  this.destroyCursors();
40430
40593
  }
40594
+ /**
40595
+ *
40596
+ * @returns true if a new player was created, false if no player was created (includes destroy & reuse of the current one)
40597
+ */
40431
40598
  setupOrDestroyPlayer() {
40432
40599
  let mode = this.settings.player.playerMode;
40433
40600
  if (mode === exports.PlayerMode.EnabledAutomatic) {
@@ -40445,6 +40612,7 @@
40445
40612
  let newPlayer = null;
40446
40613
  if (mode !== this._actualPlayerMode) {
40447
40614
  this.destroyPlayer();
40615
+ this.updateCursors();
40448
40616
  switch (mode) {
40449
40617
  case exports.PlayerMode.Disabled:
40450
40618
  newPlayer = null;
@@ -40462,9 +40630,9 @@
40462
40630
  }
40463
40631
  else {
40464
40632
  // no change in player mode, just update song info if needed
40465
- return true;
40633
+ this.updateCursors();
40634
+ return false;
40466
40635
  }
40467
- this.updateCursors();
40468
40636
  this._actualPlayerMode = mode;
40469
40637
  if (!newPlayer) {
40470
40638
  return false;
@@ -40472,6 +40640,13 @@
40472
40640
  this._player.instance = newPlayer;
40473
40641
  return false;
40474
40642
  }
40643
+ /**
40644
+ * Re-creates the midi for the current score and loads it.
40645
+ * @remarks
40646
+ * This will result in the player to stop playback. Some setting changes require re-genration of the midi song.
40647
+ * @category Methods - Player
40648
+ * @since 1.6.0
40649
+ */
40475
40650
  loadMidiForScore() {
40476
40651
  if (!this.score) {
40477
40652
  return;
@@ -40875,6 +41050,7 @@
40875
41050
  this._barCursor = cursors.barCursor;
40876
41051
  this._beatCursor = cursors.beatCursor;
40877
41052
  this._selectionWrapper = cursors.selectionWrapper;
41053
+ this._isInitialBeatCursorUpdate = true;
40878
41054
  }
40879
41055
  if (this._currentBeat !== null) {
40880
41056
  this.cursorUpdateBeat(this._currentBeat, false, this._previousTick > 10, 1, true);
@@ -40914,7 +41090,7 @@
40914
41090
  if (!beat) {
40915
41091
  return;
40916
41092
  }
40917
- const cache = this.renderer.boundsLookup;
41093
+ const cache = this._renderer.boundsLookup;
40918
41094
  if (!cache) {
40919
41095
  return;
40920
41096
  }
@@ -41037,6 +41213,7 @@
41037
41213
  if (isPlayingUpdate) {
41038
41214
  // we do not "reset" the cursor if we are smoothly moving from left to right.
41039
41215
  const jumpCursor = !previousBeatBounds ||
41216
+ this._isInitialBeatCursorUpdate ||
41040
41217
  barBounds.y !== previousBeatBounds.barBounds.masterBarBounds.visualBounds.y ||
41041
41218
  startBeatX < previousBeatBounds.onNotesX ||
41042
41219
  barBoundings.index > previousBeatBounds.barBounds.masterBarBounds.index + 1;
@@ -41061,13 +41238,16 @@
41061
41238
  }
41062
41239
  else {
41063
41240
  // ticking cursor
41241
+ beatCursor.transitionToX(0, startBeatX);
41064
41242
  beatCursor.setBounds(startBeatX, barBounds.y, 1, barBounds.h);
41065
41243
  }
41244
+ this._isInitialBeatCursorUpdate = false;
41066
41245
  }
41067
- // if playing, animate the cursor to the next beat
41068
- if (this.settings.player.enableElementHighlighting) {
41069
- this.uiFacade.removeHighlights();
41246
+ else {
41247
+ this._isInitialBeatCursorUpdate = true;
41070
41248
  }
41249
+ // if playing, animate the cursor to the next beat
41250
+ this.uiFacade.removeHighlights();
41071
41251
  // actively playing? -> animate cursor and highlight items
41072
41252
  let shouldNotifyBeatChange = false;
41073
41253
  if (isPlayingUpdate) {
@@ -41231,11 +41411,11 @@
41231
41411
  }
41232
41412
  const relX = e.getX(this.canvasElement);
41233
41413
  const relY = e.getY(this.canvasElement);
41234
- const beat = this.renderer.boundsLookup?.getBeatAtPos(relX, relY) ?? null;
41414
+ const beat = this._renderer.boundsLookup?.getBeatAtPos(relX, relY) ?? null;
41235
41415
  if (beat) {
41236
41416
  this.onBeatMouseDown(e, beat);
41237
41417
  if (this.settings.core.includeNoteBounds) {
41238
- const note = this.renderer.boundsLookup?.getNoteAtPos(beat, relX, relY);
41418
+ const note = this._renderer.boundsLookup?.getNoteAtPos(beat, relX, relY);
41239
41419
  if (note) {
41240
41420
  this.onNoteMouseDown(e, note);
41241
41421
  }
@@ -41248,11 +41428,11 @@
41248
41428
  }
41249
41429
  const relX = e.getX(this.canvasElement);
41250
41430
  const relY = e.getY(this.canvasElement);
41251
- const beat = this.renderer.boundsLookup?.getBeatAtPos(relX, relY) ?? null;
41431
+ const beat = this._renderer.boundsLookup?.getBeatAtPos(relX, relY) ?? null;
41252
41432
  if (beat) {
41253
41433
  this.onBeatMouseMove(e, beat);
41254
41434
  if (this._noteMouseDown) {
41255
- const note = this.renderer.boundsLookup?.getNoteAtPos(beat, relX, relY);
41435
+ const note = this._renderer.boundsLookup?.getNoteAtPos(beat, relX, relY);
41256
41436
  if (note) {
41257
41437
  this.onNoteMouseMove(e, note);
41258
41438
  }
@@ -41268,11 +41448,11 @@
41268
41448
  }
41269
41449
  const relX = e.getX(this.canvasElement);
41270
41450
  const relY = e.getY(this.canvasElement);
41271
- const beat = this.renderer.boundsLookup?.getBeatAtPos(relX, relY) ?? null;
41451
+ const beat = this._renderer.boundsLookup?.getBeatAtPos(relX, relY) ?? null;
41272
41452
  this.onBeatMouseUp(e, beat);
41273
41453
  if (this._noteMouseDown) {
41274
41454
  if (beat) {
41275
- const note = this.renderer.boundsLookup?.getNoteAtPos(beat, relX, relY) ?? null;
41455
+ const note = this._renderer.boundsLookup?.getNoteAtPos(beat, relX, relY) ?? null;
41276
41456
  this.onNoteMouseUp(e, note);
41277
41457
  }
41278
41458
  else {
@@ -41280,7 +41460,7 @@
41280
41460
  }
41281
41461
  }
41282
41462
  });
41283
- this.renderer.postRenderFinished.on(() => {
41463
+ this._renderer.postRenderFinished.on(() => {
41284
41464
  if (!this._selectionStart ||
41285
41465
  this.settings.player.playerMode === exports.PlayerMode.Disabled ||
41286
41466
  !this.settings.player.enableCursor ||
@@ -41291,7 +41471,7 @@
41291
41471
  });
41292
41472
  }
41293
41473
  cursorSelectRange(startBeat, endBeat) {
41294
- const cache = this.renderer.boundsLookup;
41474
+ const cache = this._renderer.boundsLookup;
41295
41475
  if (!cache) {
41296
41476
  return;
41297
41477
  }
@@ -41360,7 +41540,8 @@
41360
41540
  }
41361
41541
  this.scoreLoaded.trigger(score);
41362
41542
  this.uiFacade.triggerEvent(this.container, 'scoreLoaded', score);
41363
- if (this.setupOrDestroyPlayer()) {
41543
+ if (!this.setupOrDestroyPlayer()) {
41544
+ // feed midi into current player (a new player will trigger a midi generation once the player is ready)
41364
41545
  this.loadMidiForScore();
41365
41546
  }
41366
41547
  }
@@ -41390,7 +41571,7 @@
41390
41571
  return;
41391
41572
  }
41392
41573
  this._currentBeat = null;
41393
- this.cursorUpdateTick(this._previousTick, false, 1, this._previousTick > 10);
41574
+ this.cursorUpdateTick(this._previousTick, false, 1, true, true);
41394
41575
  this.postRenderFinished.trigger();
41395
41576
  this.uiFacade.triggerEvent(this.container, 'postRenderFinished', null);
41396
41577
  }
@@ -46946,7 +47127,7 @@
46946
47127
  return this.masterBarsRenderers[0].masterBar.index;
46947
47128
  }
46948
47129
  get lastBarIndex() {
46949
- return this.masterBarsRenderers[this.masterBarsRenderers.length - 1].masterBar.index;
47130
+ return this.masterBarsRenderers[this.masterBarsRenderers.length - 1].lastMasterBarIndex;
46950
47131
  }
46951
47132
  addMasterBarRenderers(tracks, renderers) {
46952
47133
  if (tracks.length === 0) {
@@ -47760,6 +47941,9 @@
47760
47941
  }
47761
47942
  }
47762
47943
  }
47944
+ else {
47945
+ this.tuningGlyph = null;
47946
+ }
47763
47947
  }
47764
47948
  // chord diagram glyphs
47765
47949
  if (notation.isNotationElementVisible(exports.NotationElement.ChordDiagrams)) {
@@ -47788,6 +47972,12 @@
47788
47972
  }
47789
47973
  }
47790
47974
  }
47975
+ if (this.chordDiagrams.isEmpty) {
47976
+ this.chordDiagrams = null;
47977
+ }
47978
+ }
47979
+ else {
47980
+ this.chordDiagrams = null;
47791
47981
  }
47792
47982
  }
47793
47983
  createEmptyStaffSystem() {
@@ -60531,9 +60721,9 @@
60531
60721
  print(`build date: ${VersionInfo.date}`);
60532
60722
  }
60533
60723
  }
60534
- VersionInfo.version = '1.6.0-alpha.1409';
60535
- VersionInfo.date = '2025-05-14T02:06:32.990Z';
60536
- VersionInfo.commit = 'f91fed13b0a0946b3fa9306b480ddf8044b948e2';
60724
+ VersionInfo.version = '1.6.0-alpha.1415';
60725
+ VersionInfo.date = '2025-05-19T16:08:22.342Z';
60726
+ VersionInfo.commit = '459db69f8896a2ea8822ce5d49dcc824edd36521';
60537
60727
 
60538
60728
  /**
60539
60729
  * A factory for custom layout engines.