@coderline/alphatab 1.6.0-alpha.1408 → 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.core.min.mjs +2 -2
- package/dist/alphaTab.core.mjs +1163 -758
- package/dist/alphaTab.d.ts +94 -20
- package/dist/alphaTab.js +1163 -758
- package/dist/alphaTab.min.js +2 -2
- package/dist/alphaTab.min.mjs +1 -1
- package/dist/alphaTab.mjs +1 -1
- package/dist/alphaTab.vite.js +1 -1
- package/dist/alphaTab.vite.mjs +1 -1
- package/dist/alphaTab.webpack.js +1 -1
- package/dist/alphaTab.webpack.mjs +1 -1
- package/dist/alphaTab.worker.min.mjs +1 -1
- package/dist/alphaTab.worker.mjs +1 -1
- package/dist/alphaTab.worklet.min.mjs +1 -1
- package/dist/alphaTab.worklet.mjs +1 -1
- package/package.json +1 -1
package/dist/alphaTab.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* alphaTab v1.6.0-alpha.
|
|
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 &&
|
|
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
|
-
|
|
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);
|
|
@@ -22403,6 +22415,11 @@
|
|
|
22403
22415
|
this._mainState.eventIndex = 0;
|
|
22404
22416
|
this._mainState.syncPointIndex = 0;
|
|
22405
22417
|
this._mainState.tempoChangeIndex = 0;
|
|
22418
|
+
this._mainState.currentTempo = this._mainState.tempoChanges[0].bpm;
|
|
22419
|
+
this._mainState.modifiedTempo =
|
|
22420
|
+
this._mainState.syncPoints.length > 0
|
|
22421
|
+
? this._mainState.syncPoints[0].data.modifiedTempo
|
|
22422
|
+
: this._mainState.currentTempo;
|
|
22406
22423
|
if (this.isPlayingMain) {
|
|
22407
22424
|
const metronomeVolume = this._synthesizer.metronomeVolume;
|
|
22408
22425
|
this._synthesizer.noteOffAll(true);
|
|
@@ -22541,18 +22558,6 @@
|
|
|
22541
22558
|
this._currentState.synthData[this._currentState.eventIndex].time < this._currentState.currentTime) {
|
|
22542
22559
|
const synthEvent = this._currentState.synthData[this._currentState.eventIndex];
|
|
22543
22560
|
this._synthesizer.dispatchEvent(synthEvent);
|
|
22544
|
-
while (this._currentState.syncPointIndex < this._currentState.syncPoints.length &&
|
|
22545
|
-
this._currentState.syncPoints[this._currentState.syncPointIndex].tick < synthEvent.event.tick) {
|
|
22546
|
-
this._currentState.modifiedTempo =
|
|
22547
|
-
this._currentState.syncPoints[this._currentState.syncPointIndex].data.modifiedTempo;
|
|
22548
|
-
this._currentState.syncPointIndex++;
|
|
22549
|
-
}
|
|
22550
|
-
while (this._currentState.tempoChangeIndex < this._currentState.tempoChanges.length &&
|
|
22551
|
-
this._currentState.tempoChanges[this._currentState.tempoChangeIndex].time <= synthEvent.time) {
|
|
22552
|
-
this._currentState.currentTempo =
|
|
22553
|
-
this._currentState.tempoChanges[this._currentState.tempoChangeIndex].bpm;
|
|
22554
|
-
this._currentState.tempoChangeIndex++;
|
|
22555
|
-
}
|
|
22556
22561
|
this._currentState.eventIndex++;
|
|
22557
22562
|
anyEventsDispatched = true;
|
|
22558
22563
|
}
|
|
@@ -22582,9 +22587,6 @@
|
|
|
22582
22587
|
mainTickPositionToTimePosition(tickPosition) {
|
|
22583
22588
|
return this.tickPositionToTimePositionWithSpeed(this._mainState, tickPosition, this.playbackSpeed);
|
|
22584
22589
|
}
|
|
22585
|
-
mainTimePositionToTickPosition(timePosition) {
|
|
22586
|
-
return this.timePositionToTickPositionWithSpeed(this._mainState, timePosition, this.playbackSpeed);
|
|
22587
|
-
}
|
|
22588
22590
|
mainUpdateSyncPoints(syncPoints) {
|
|
22589
22591
|
const state = this._mainState;
|
|
22590
22592
|
syncPoints.sort((a, b) => a.tick - b.tick); // just in case
|
|
@@ -22612,7 +22614,49 @@
|
|
|
22612
22614
|
state.syncPointIndex = 0;
|
|
22613
22615
|
}
|
|
22614
22616
|
currentTimePositionToTickPosition(timePosition) {
|
|
22615
|
-
|
|
22617
|
+
const state = this._currentState;
|
|
22618
|
+
if (state.tempoChanges.length === 0) {
|
|
22619
|
+
return 0;
|
|
22620
|
+
}
|
|
22621
|
+
timePosition *= this.playbackSpeed;
|
|
22622
|
+
this.updateCurrentTempo(state, timePosition);
|
|
22623
|
+
const lastTempoChange = state.tempoChanges[state.tempoChangeIndex];
|
|
22624
|
+
const timeDiff = timePosition - lastTempoChange.time;
|
|
22625
|
+
const ticks = ((timeDiff / (60000.0 / (lastTempoChange.bpm * state.division))) | 0);
|
|
22626
|
+
// we add 1 for possible rounding errors.(floating point issuses)
|
|
22627
|
+
return lastTempoChange.ticks + ticks + 1;
|
|
22628
|
+
}
|
|
22629
|
+
updateCurrentTempo(state, timePosition) {
|
|
22630
|
+
let tempoChangeIndex = state.tempoChangeIndex;
|
|
22631
|
+
if (timePosition < state.tempoChanges[tempoChangeIndex].time) {
|
|
22632
|
+
tempoChangeIndex = 0;
|
|
22633
|
+
}
|
|
22634
|
+
while (tempoChangeIndex + 1 < state.tempoChanges.length &&
|
|
22635
|
+
state.tempoChanges[tempoChangeIndex + 1].time <= timePosition) {
|
|
22636
|
+
tempoChangeIndex++;
|
|
22637
|
+
}
|
|
22638
|
+
if (tempoChangeIndex !== state.tempoChangeIndex) {
|
|
22639
|
+
state.tempoChangeIndex = tempoChangeIndex;
|
|
22640
|
+
state.currentTempo = state.tempoChanges[state.tempoChangeIndex].bpm;
|
|
22641
|
+
}
|
|
22642
|
+
const syncPoints = state.syncPoints;
|
|
22643
|
+
if (syncPoints.length > 0) {
|
|
22644
|
+
let syncPointIndex = Math.min(state.syncPointIndex, syncPoints.length - 1);
|
|
22645
|
+
if (timePosition < syncPoints[syncPointIndex].data.millisecondOffset) {
|
|
22646
|
+
syncPointIndex = 0;
|
|
22647
|
+
}
|
|
22648
|
+
while (syncPointIndex + 1 < syncPoints.length &&
|
|
22649
|
+
syncPoints[syncPointIndex + 1].data.millisecondOffset <= timePosition) {
|
|
22650
|
+
syncPointIndex++;
|
|
22651
|
+
}
|
|
22652
|
+
if (syncPointIndex !== state.syncPointIndex) {
|
|
22653
|
+
state.syncPointIndex = syncPointIndex;
|
|
22654
|
+
state.modifiedTempo = syncPoints[syncPointIndex].data.modifiedTempo;
|
|
22655
|
+
}
|
|
22656
|
+
}
|
|
22657
|
+
else {
|
|
22658
|
+
state.modifiedTempo = state.currentTempo;
|
|
22659
|
+
}
|
|
22616
22660
|
}
|
|
22617
22661
|
mainTimePositionFromBackingTrack(timePosition, backingTrackLength) {
|
|
22618
22662
|
const mainState = this._mainState;
|
|
@@ -22620,11 +22664,8 @@
|
|
|
22620
22664
|
if (timePosition < 0 || syncPoints.length === 0) {
|
|
22621
22665
|
return timePosition;
|
|
22622
22666
|
}
|
|
22623
|
-
|
|
22624
|
-
|
|
22625
|
-
syncPoints[syncPointIndex + 1].data.millisecondOffset <= timePosition) {
|
|
22626
|
-
syncPointIndex++;
|
|
22627
|
-
}
|
|
22667
|
+
this.updateCurrentTempo(this._mainState, timePosition);
|
|
22668
|
+
const syncPointIndex = Math.min(mainState.syncPointIndex, syncPoints.length - 1);
|
|
22628
22669
|
const currentSyncPoint = syncPoints[syncPointIndex];
|
|
22629
22670
|
const timeDiff = timePosition - currentSyncPoint.data.millisecondOffset;
|
|
22630
22671
|
let alphaTabTimeDiff;
|
|
@@ -22646,7 +22687,10 @@
|
|
|
22646
22687
|
return timePosition;
|
|
22647
22688
|
}
|
|
22648
22689
|
timePosition *= this.playbackSpeed;
|
|
22649
|
-
let syncPointIndex =
|
|
22690
|
+
let syncPointIndex = Math.min(mainState.syncPointIndex, syncPoints.length - 1);
|
|
22691
|
+
if (timePosition < syncPoints[syncPointIndex].time) {
|
|
22692
|
+
syncPointIndex = 0;
|
|
22693
|
+
}
|
|
22650
22694
|
while (syncPointIndex + 1 < syncPoints.length && syncPoints[syncPointIndex + 1].time <= timePosition) {
|
|
22651
22695
|
syncPointIndex++;
|
|
22652
22696
|
}
|
|
@@ -22684,26 +22728,6 @@
|
|
|
22684
22728
|
timePosition += tickPosition * (60000.0 / (bpm * state.division));
|
|
22685
22729
|
return timePosition / playbackSpeed;
|
|
22686
22730
|
}
|
|
22687
|
-
timePositionToTickPositionWithSpeed(state, timePosition, playbackSpeed) {
|
|
22688
|
-
timePosition *= playbackSpeed;
|
|
22689
|
-
let ticks = 0;
|
|
22690
|
-
let bpm = 120.0;
|
|
22691
|
-
let lastChange = 0;
|
|
22692
|
-
// find start and bpm of last tempo change before time
|
|
22693
|
-
for (const c of state.tempoChanges) {
|
|
22694
|
-
if (timePosition < c.time) {
|
|
22695
|
-
break;
|
|
22696
|
-
}
|
|
22697
|
-
ticks = c.ticks;
|
|
22698
|
-
bpm = c.bpm;
|
|
22699
|
-
lastChange = c.time;
|
|
22700
|
-
}
|
|
22701
|
-
// add the missing ticks
|
|
22702
|
-
timePosition -= lastChange;
|
|
22703
|
-
ticks += (timePosition / (60000.0 / (bpm * state.division))) | 0;
|
|
22704
|
-
// we add 1 for possible rounding errors.(floating point issuses)
|
|
22705
|
-
return ticks + 1;
|
|
22706
|
-
}
|
|
22707
22731
|
get internalEndTime() {
|
|
22708
22732
|
if (this.isPlayingMain) {
|
|
22709
22733
|
return !this.mainPlaybackRange ? this._currentState.endTime : this._currentState.playbackRangeEndTime;
|
|
@@ -26922,7 +26946,7 @@
|
|
|
26922
26946
|
return processedEvents;
|
|
26923
26947
|
}
|
|
26924
26948
|
processMidiMessage(e) {
|
|
26925
|
-
Logger.debug('Midi', `Processing Midi message ${MidiEventType[e.type]}/${e.tick}`);
|
|
26949
|
+
//Logger.debug('Midi', `Processing Midi message ${MidiEventType[e.type]}/${e.tick}`);
|
|
26926
26950
|
const command = e.type;
|
|
26927
26951
|
switch (command) {
|
|
26928
26952
|
case MidiEventType.TimeSignature:
|
|
@@ -28043,6 +28067,9 @@
|
|
|
28043
28067
|
}
|
|
28044
28068
|
on(value) {
|
|
28045
28069
|
this._listeners.push(value);
|
|
28070
|
+
return () => {
|
|
28071
|
+
this.off(value);
|
|
28072
|
+
};
|
|
28046
28073
|
}
|
|
28047
28074
|
off(value) {
|
|
28048
28075
|
this._listeners = this._listeners.filter(l => l !== value);
|
|
@@ -28062,6 +28089,9 @@
|
|
|
28062
28089
|
}
|
|
28063
28090
|
on(value) {
|
|
28064
28091
|
this._listeners.push(value);
|
|
28092
|
+
return () => {
|
|
28093
|
+
this.off(value);
|
|
28094
|
+
};
|
|
28065
28095
|
}
|
|
28066
28096
|
off(value) {
|
|
28067
28097
|
this._listeners = this._listeners.filter(l => l !== value);
|
|
@@ -28458,7 +28488,7 @@
|
|
|
28458
28488
|
endTick = this.sequencer.currentEndTick;
|
|
28459
28489
|
}
|
|
28460
28490
|
if (this._tickPosition >= endTick) {
|
|
28461
|
-
// fully done with playback of remaining samples?
|
|
28491
|
+
// fully done with playback of remaining samples?
|
|
28462
28492
|
if (this._notPlayedSamples <= 0) {
|
|
28463
28493
|
this._notPlayedSamples = 0;
|
|
28464
28494
|
if (this.sequencer.isPlayingCountIn) {
|
|
@@ -35808,6 +35838,27 @@
|
|
|
35808
35838
|
controller.moveNext();
|
|
35809
35839
|
previousMasterBar = bar;
|
|
35810
35840
|
}
|
|
35841
|
+
// here we interpolate the sync point which marks the end of the sync.
|
|
35842
|
+
// Sync points define new tempos at certain positions.
|
|
35843
|
+
// looking from the last sync point to the end we do not assume the end where the audio ends,
|
|
35844
|
+
// but where it ends according to the BPM and the remaining ticks.
|
|
35845
|
+
if (this.syncPoints.length > 0) {
|
|
35846
|
+
const lastSyncPoint = this.syncPoints[this.syncPoints.length - 1];
|
|
35847
|
+
const endTick = controller.currentTick;
|
|
35848
|
+
const remainingTicks = endTick - lastSyncPoint.tick;
|
|
35849
|
+
if (remainingTicks > 0) {
|
|
35850
|
+
const syncPointData = new SyncPointData();
|
|
35851
|
+
// last occurence of the last bar
|
|
35852
|
+
syncPointData.barOccurence = barOccurence.get(this._score.masterBars.length - 1);
|
|
35853
|
+
// same tempo as last point
|
|
35854
|
+
syncPointData.modifiedTempo = lastSyncPoint.data.modifiedTempo;
|
|
35855
|
+
// interpolated end from last syncPoint
|
|
35856
|
+
syncPointData.millisecondOffset =
|
|
35857
|
+
lastSyncPoint.data.millisecondOffset +
|
|
35858
|
+
MidiUtils.ticksToMillis(remainingTicks, syncPointData.modifiedTempo);
|
|
35859
|
+
this.syncPoints.push(new BackingTrackSyncPoint(endTick, syncPointData));
|
|
35860
|
+
}
|
|
35861
|
+
}
|
|
35811
35862
|
for (const track of this._score.tracks) {
|
|
35812
35863
|
this._handler.finishTrack(track.index, controller.currentTick);
|
|
35813
35864
|
}
|
|
@@ -38299,6 +38350,357 @@
|
|
|
38299
38350
|
}
|
|
38300
38351
|
}
|
|
38301
38352
|
|
|
38353
|
+
/**
|
|
38354
|
+
* A {@link IAlphaSynth} implementation wrapping and underling other {@link IAlphaSynth}
|
|
38355
|
+
* allowing dynamic changing of the underlying instance without loosing aspects like the
|
|
38356
|
+
* main playback information and event listeners.
|
|
38357
|
+
*
|
|
38358
|
+
* @remarks
|
|
38359
|
+
* This wrapper is used when re-exposing the underlying player via {@link AlphaTabApiBase} to integrators.
|
|
38360
|
+
* Even with dynamic switching between synthesizer, backing tracks etc. aspects like volume, playbackspeed,
|
|
38361
|
+
* event listeners etc. should not be lost.
|
|
38362
|
+
*/
|
|
38363
|
+
class AlphaSynthWrapper {
|
|
38364
|
+
constructor() {
|
|
38365
|
+
// relevant state information we want to remember when switching between player instances
|
|
38366
|
+
this._masterVolume = 1;
|
|
38367
|
+
this._metronomeVolume = 0;
|
|
38368
|
+
this._countInVolume = 0;
|
|
38369
|
+
this._playbackSpeed = 1;
|
|
38370
|
+
this._isLooping = false;
|
|
38371
|
+
this._midiEventsPlayedFilter = [];
|
|
38372
|
+
this.ready = new EventEmitter();
|
|
38373
|
+
this.readyForPlayback = new EventEmitter();
|
|
38374
|
+
this.finished = new EventEmitter();
|
|
38375
|
+
this.soundFontLoaded = new EventEmitter();
|
|
38376
|
+
this.soundFontLoadFailed = new EventEmitterOfT();
|
|
38377
|
+
this.midiLoaded = new EventEmitterOfT();
|
|
38378
|
+
this.midiLoadFailed = new EventEmitterOfT();
|
|
38379
|
+
this.stateChanged = new EventEmitterOfT();
|
|
38380
|
+
this.positionChanged = new EventEmitterOfT();
|
|
38381
|
+
this.midiEventsPlayed = new EventEmitterOfT();
|
|
38382
|
+
this.playbackRangeChanged = new EventEmitterOfT();
|
|
38383
|
+
}
|
|
38384
|
+
get instance() {
|
|
38385
|
+
return this._instance;
|
|
38386
|
+
}
|
|
38387
|
+
set instance(value) {
|
|
38388
|
+
this._instance = value;
|
|
38389
|
+
// unregister all events from previous instance
|
|
38390
|
+
const unregister = this._instanceEventUnregister;
|
|
38391
|
+
if (unregister) {
|
|
38392
|
+
for (const e of unregister) {
|
|
38393
|
+
e();
|
|
38394
|
+
}
|
|
38395
|
+
}
|
|
38396
|
+
if (value) {
|
|
38397
|
+
// regsiter to events of new player and forward them to existing listeners
|
|
38398
|
+
const newUnregister = [];
|
|
38399
|
+
newUnregister.push(value.ready.on(() => this.ready.trigger()));
|
|
38400
|
+
newUnregister.push(value.readyForPlayback.on(() => this.readyForPlayback.trigger()));
|
|
38401
|
+
newUnregister.push(value.finished.on(() => this.finished.trigger()));
|
|
38402
|
+
newUnregister.push(value.soundFontLoaded.on(() => this.soundFontLoaded.trigger()));
|
|
38403
|
+
newUnregister.push(value.soundFontLoadFailed.on(e => this.soundFontLoadFailed.trigger(e)));
|
|
38404
|
+
newUnregister.push(value.midiLoaded.on(e => this.midiLoaded.trigger(e)));
|
|
38405
|
+
newUnregister.push(value.midiLoadFailed.on(e => this.midiLoadFailed.trigger(e)));
|
|
38406
|
+
newUnregister.push(value.stateChanged.on(e => this.stateChanged.trigger(e)));
|
|
38407
|
+
newUnregister.push(value.positionChanged.on(e => this.positionChanged.trigger(e)));
|
|
38408
|
+
newUnregister.push(value.midiEventsPlayed.on(e => this.midiEventsPlayed.trigger(e)));
|
|
38409
|
+
newUnregister.push(value.playbackRangeChanged.on(e => this.playbackRangeChanged.trigger(e)));
|
|
38410
|
+
this._instanceEventUnregister = newUnregister;
|
|
38411
|
+
// restore state on new player
|
|
38412
|
+
if (this.isReady) {
|
|
38413
|
+
value.masterVolume = this._masterVolume;
|
|
38414
|
+
value.metronomeVolume = this._metronomeVolume;
|
|
38415
|
+
value.countInVolume = this._countInVolume;
|
|
38416
|
+
value.playbackSpeed = this._playbackSpeed;
|
|
38417
|
+
value.isLooping = this._isLooping;
|
|
38418
|
+
value.midiEventsPlayedFilter = this._midiEventsPlayedFilter;
|
|
38419
|
+
}
|
|
38420
|
+
else {
|
|
38421
|
+
newUnregister.push(value.ready.on(() => {
|
|
38422
|
+
value.masterVolume = this._masterVolume;
|
|
38423
|
+
value.metronomeVolume = this._metronomeVolume;
|
|
38424
|
+
value.countInVolume = this._countInVolume;
|
|
38425
|
+
value.playbackSpeed = this._playbackSpeed;
|
|
38426
|
+
value.isLooping = this._isLooping;
|
|
38427
|
+
value.midiEventsPlayedFilter = this._midiEventsPlayedFilter;
|
|
38428
|
+
}));
|
|
38429
|
+
}
|
|
38430
|
+
}
|
|
38431
|
+
else {
|
|
38432
|
+
this._instanceEventUnregister = undefined;
|
|
38433
|
+
}
|
|
38434
|
+
}
|
|
38435
|
+
get output() {
|
|
38436
|
+
return this._instance.output;
|
|
38437
|
+
}
|
|
38438
|
+
get isReady() {
|
|
38439
|
+
return this._instance ? this._instance.isReady : false;
|
|
38440
|
+
}
|
|
38441
|
+
get isReadyForPlayback() {
|
|
38442
|
+
return this._instance ? this._instance.isReadyForPlayback : false;
|
|
38443
|
+
}
|
|
38444
|
+
get state() {
|
|
38445
|
+
return this._instance ? this._instance.state : PlayerState.Paused;
|
|
38446
|
+
}
|
|
38447
|
+
get logLevel() {
|
|
38448
|
+
return Logger.logLevel;
|
|
38449
|
+
}
|
|
38450
|
+
set logLevel(value) {
|
|
38451
|
+
Logger.logLevel = value;
|
|
38452
|
+
if (this._instance) {
|
|
38453
|
+
this._instance.logLevel = value;
|
|
38454
|
+
}
|
|
38455
|
+
}
|
|
38456
|
+
get masterVolume() {
|
|
38457
|
+
return this._masterVolume;
|
|
38458
|
+
}
|
|
38459
|
+
set masterVolume(value) {
|
|
38460
|
+
value = Math.max(value, SynthConstants.MinVolume);
|
|
38461
|
+
this._masterVolume = value;
|
|
38462
|
+
if (this._instance) {
|
|
38463
|
+
this._instance.masterVolume = value;
|
|
38464
|
+
}
|
|
38465
|
+
}
|
|
38466
|
+
get metronomeVolume() {
|
|
38467
|
+
return this._metronomeVolume;
|
|
38468
|
+
}
|
|
38469
|
+
set metronomeVolume(value) {
|
|
38470
|
+
value = Math.max(value, SynthConstants.MinVolume);
|
|
38471
|
+
this._metronomeVolume = value;
|
|
38472
|
+
if (this._instance) {
|
|
38473
|
+
this._instance.metronomeVolume = value;
|
|
38474
|
+
}
|
|
38475
|
+
}
|
|
38476
|
+
get playbackSpeed() {
|
|
38477
|
+
return this._playbackSpeed;
|
|
38478
|
+
}
|
|
38479
|
+
set playbackSpeed(value) {
|
|
38480
|
+
this._playbackSpeed = value;
|
|
38481
|
+
if (this._instance) {
|
|
38482
|
+
this._instance.playbackSpeed = value;
|
|
38483
|
+
}
|
|
38484
|
+
}
|
|
38485
|
+
get tickPosition() {
|
|
38486
|
+
return this._instance ? this._instance.tickPosition : 0;
|
|
38487
|
+
}
|
|
38488
|
+
set tickPosition(value) {
|
|
38489
|
+
if (this._instance) {
|
|
38490
|
+
this._instance.tickPosition = value;
|
|
38491
|
+
}
|
|
38492
|
+
}
|
|
38493
|
+
get timePosition() {
|
|
38494
|
+
return this._instance ? this._instance.timePosition : 0;
|
|
38495
|
+
}
|
|
38496
|
+
set timePosition(value) {
|
|
38497
|
+
if (this._instance) {
|
|
38498
|
+
this._instance.timePosition = value;
|
|
38499
|
+
}
|
|
38500
|
+
}
|
|
38501
|
+
get playbackRange() {
|
|
38502
|
+
return this._instance ? this._instance.playbackRange : null;
|
|
38503
|
+
}
|
|
38504
|
+
set playbackRange(value) {
|
|
38505
|
+
if (this._instance) {
|
|
38506
|
+
this._instance.playbackRange = value;
|
|
38507
|
+
}
|
|
38508
|
+
}
|
|
38509
|
+
get isLooping() {
|
|
38510
|
+
return this._isLooping;
|
|
38511
|
+
}
|
|
38512
|
+
set isLooping(value) {
|
|
38513
|
+
this._isLooping = value;
|
|
38514
|
+
if (this._instance) {
|
|
38515
|
+
this._instance.isLooping = value;
|
|
38516
|
+
}
|
|
38517
|
+
}
|
|
38518
|
+
get countInVolume() {
|
|
38519
|
+
return this._countInVolume;
|
|
38520
|
+
}
|
|
38521
|
+
set countInVolume(value) {
|
|
38522
|
+
this._countInVolume = value;
|
|
38523
|
+
if (this._instance) {
|
|
38524
|
+
this._instance.countInVolume = value;
|
|
38525
|
+
}
|
|
38526
|
+
}
|
|
38527
|
+
get midiEventsPlayedFilter() {
|
|
38528
|
+
return this._midiEventsPlayedFilter;
|
|
38529
|
+
}
|
|
38530
|
+
set midiEventsPlayedFilter(value) {
|
|
38531
|
+
this._midiEventsPlayedFilter = value;
|
|
38532
|
+
if (this._instance) {
|
|
38533
|
+
this._instance.midiEventsPlayedFilter = value;
|
|
38534
|
+
}
|
|
38535
|
+
}
|
|
38536
|
+
destroy() {
|
|
38537
|
+
if (this._instance) {
|
|
38538
|
+
this._instance.destroy();
|
|
38539
|
+
this._instance = undefined;
|
|
38540
|
+
}
|
|
38541
|
+
}
|
|
38542
|
+
play() {
|
|
38543
|
+
return this._instance ? this._instance.play() : false;
|
|
38544
|
+
}
|
|
38545
|
+
pause() {
|
|
38546
|
+
if (this._instance) {
|
|
38547
|
+
this._instance.pause();
|
|
38548
|
+
}
|
|
38549
|
+
}
|
|
38550
|
+
playPause() {
|
|
38551
|
+
if (this._instance) {
|
|
38552
|
+
this._instance.playPause();
|
|
38553
|
+
}
|
|
38554
|
+
}
|
|
38555
|
+
stop() {
|
|
38556
|
+
if (this._instance) {
|
|
38557
|
+
this._instance.stop();
|
|
38558
|
+
}
|
|
38559
|
+
}
|
|
38560
|
+
playOneTimeMidiFile(midi) {
|
|
38561
|
+
if (this._instance) {
|
|
38562
|
+
this._instance.playOneTimeMidiFile(midi);
|
|
38563
|
+
}
|
|
38564
|
+
}
|
|
38565
|
+
loadSoundFont(data, append) {
|
|
38566
|
+
if (this._instance) {
|
|
38567
|
+
this._instance.loadSoundFont(data, append);
|
|
38568
|
+
}
|
|
38569
|
+
}
|
|
38570
|
+
resetSoundFonts() {
|
|
38571
|
+
if (this._instance) {
|
|
38572
|
+
this._instance.resetSoundFonts();
|
|
38573
|
+
}
|
|
38574
|
+
}
|
|
38575
|
+
loadMidiFile(midi) {
|
|
38576
|
+
if (this._instance) {
|
|
38577
|
+
this._instance.loadMidiFile(midi);
|
|
38578
|
+
}
|
|
38579
|
+
}
|
|
38580
|
+
loadBackingTrack(score, syncPoints) {
|
|
38581
|
+
if (this._instance) {
|
|
38582
|
+
this._instance.loadBackingTrack(score, syncPoints);
|
|
38583
|
+
}
|
|
38584
|
+
}
|
|
38585
|
+
applyTranspositionPitches(transpositionPitches) {
|
|
38586
|
+
if (this._instance) {
|
|
38587
|
+
this._instance.applyTranspositionPitches(transpositionPitches);
|
|
38588
|
+
}
|
|
38589
|
+
}
|
|
38590
|
+
setChannelTranspositionPitch(channel, semitones) {
|
|
38591
|
+
if (this._instance) {
|
|
38592
|
+
this._instance.setChannelTranspositionPitch(channel, semitones);
|
|
38593
|
+
}
|
|
38594
|
+
}
|
|
38595
|
+
setChannelMute(channel, mute) {
|
|
38596
|
+
if (this._instance) {
|
|
38597
|
+
this._instance.setChannelMute(channel, mute);
|
|
38598
|
+
}
|
|
38599
|
+
}
|
|
38600
|
+
resetChannelStates() {
|
|
38601
|
+
if (this._instance) {
|
|
38602
|
+
this._instance.resetChannelStates();
|
|
38603
|
+
}
|
|
38604
|
+
}
|
|
38605
|
+
setChannelSolo(channel, solo) {
|
|
38606
|
+
if (this._instance) {
|
|
38607
|
+
this._instance.setChannelSolo(channel, solo);
|
|
38608
|
+
}
|
|
38609
|
+
}
|
|
38610
|
+
setChannelVolume(channel, volume) {
|
|
38611
|
+
if (this._instance) {
|
|
38612
|
+
this._instance.setChannelVolume(channel, volume);
|
|
38613
|
+
}
|
|
38614
|
+
}
|
|
38615
|
+
}
|
|
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
|
+
|
|
38302
38704
|
class SelectionInfo {
|
|
38303
38705
|
constructor(beat) {
|
|
38304
38706
|
this.bounds = null;
|
|
@@ -38318,6 +38720,18 @@
|
|
|
38318
38720
|
get actualPlayerMode() {
|
|
38319
38721
|
return this._actualPlayerMode;
|
|
38320
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
|
+
}
|
|
38321
38735
|
/**
|
|
38322
38736
|
* The score holding all information about the song being rendered
|
|
38323
38737
|
* @category Properties - Core
|
|
@@ -38389,43 +38803,14 @@
|
|
|
38389
38803
|
this._tracks = [];
|
|
38390
38804
|
this._actualPlayerMode = exports.PlayerMode.Disabled;
|
|
38391
38805
|
this._tickCache = null;
|
|
38392
|
-
/**
|
|
38393
|
-
* The alphaSynth player used for playback.
|
|
38394
|
-
* @remarks
|
|
38395
|
-
* This is the low-level API to the Midi synthesizer used for playback.
|
|
38396
|
-
* Gets access to the underling {@link IAlphaSynth} that is used for the audio playback.
|
|
38397
|
-
* @category Properties - Player
|
|
38398
|
-
* @since 0.9.4
|
|
38399
|
-
* @example
|
|
38400
|
-
* JavaScript
|
|
38401
|
-
* ```js
|
|
38402
|
-
* const api = new alphaTab.AlphaTabApi(document.querySelector('#alphaTab'));
|
|
38403
|
-
* setupPlayerEvents(api.settings);
|
|
38404
|
-
* ```
|
|
38405
|
-
*
|
|
38406
|
-
* @example
|
|
38407
|
-
* C#
|
|
38408
|
-
* ```cs
|
|
38409
|
-
* var api = new AlphaTabApi<MyControl>(...);
|
|
38410
|
-
* SetupPlayerEvents(api.Player);
|
|
38411
|
-
* ```
|
|
38412
|
-
*
|
|
38413
|
-
* @example
|
|
38414
|
-
* Android
|
|
38415
|
-
* ```kotlin
|
|
38416
|
-
* val api = AlphaTabApi<MyControl>(...)
|
|
38417
|
-
* setupPlayerEvents(api.player)
|
|
38418
|
-
* ```
|
|
38419
|
-
*/
|
|
38420
|
-
this.player = null;
|
|
38421
38806
|
this._cursorWrapper = null;
|
|
38422
38807
|
this._barCursor = null;
|
|
38423
38808
|
this._beatCursor = null;
|
|
38424
38809
|
this._selectionWrapper = null;
|
|
38425
38810
|
this._previousTick = 0;
|
|
38426
|
-
this._playerState = PlayerState.Paused;
|
|
38427
38811
|
this._currentBeat = null;
|
|
38428
|
-
this.
|
|
38812
|
+
this._currentBeatBounds = null;
|
|
38813
|
+
this._isInitialBeatCursorUpdate = true;
|
|
38429
38814
|
this._previousStateForCursor = PlayerState.Paused;
|
|
38430
38815
|
this._previousCursorCache = null;
|
|
38431
38816
|
this._lastScroll = 0;
|
|
@@ -38996,133 +39381,6 @@
|
|
|
38996
39381
|
*
|
|
38997
39382
|
*/
|
|
38998
39383
|
this.error = new EventEmitterOfT();
|
|
38999
|
-
/**
|
|
39000
|
-
* This event is fired when all required data for playback is loaded and ready.
|
|
39001
|
-
* @remarks
|
|
39002
|
-
* This event is fired when all required data for playback is loaded and ready. The player is ready for playback when
|
|
39003
|
-
* all background workers are started, the audio output is initialized, a soundfont is loaded, and a song was loaded into the player as midi file.
|
|
39004
|
-
*
|
|
39005
|
-
* @eventProperty
|
|
39006
|
-
* @category Events - Player
|
|
39007
|
-
* @since 0.9.4
|
|
39008
|
-
*
|
|
39009
|
-
* @example
|
|
39010
|
-
* JavaScript
|
|
39011
|
-
* ```js
|
|
39012
|
-
* const api = new alphaTab.AlphaTabApi(document.querySelector('#alphaTab'));
|
|
39013
|
-
* api.playerReady.on(() => {
|
|
39014
|
-
* enablePlayerControls();
|
|
39015
|
-
* });
|
|
39016
|
-
* ```
|
|
39017
|
-
*
|
|
39018
|
-
* @example
|
|
39019
|
-
* C#
|
|
39020
|
-
* ```cs
|
|
39021
|
-
* var api = new AlphaTabApi<MyControl>(...);
|
|
39022
|
-
* api.PlayerReady.On(() =>
|
|
39023
|
-
* {
|
|
39024
|
-
* EnablePlayerControls()
|
|
39025
|
-
* });
|
|
39026
|
-
* ```
|
|
39027
|
-
*
|
|
39028
|
-
* @example
|
|
39029
|
-
* Android
|
|
39030
|
-
* ```kotlin
|
|
39031
|
-
* val api = AlphaTabApi<MyControl>(...)
|
|
39032
|
-
* api.playerReady.on {
|
|
39033
|
-
* enablePlayerControls()
|
|
39034
|
-
* }
|
|
39035
|
-
* ```
|
|
39036
|
-
*/
|
|
39037
|
-
this.playerReady = new EventEmitter();
|
|
39038
|
-
/**
|
|
39039
|
-
* This event is fired when the playback of the whole song finished.
|
|
39040
|
-
* @remarks
|
|
39041
|
-
* This event is finished regardless on whether looping is enabled or not.
|
|
39042
|
-
*
|
|
39043
|
-
* @eventProperty
|
|
39044
|
-
* @category Events - Player
|
|
39045
|
-
* @since 0.9.4
|
|
39046
|
-
*
|
|
39047
|
-
* @example
|
|
39048
|
-
* JavaScript
|
|
39049
|
-
* ```js
|
|
39050
|
-
* const api = new alphaTab.AlphaTabApi(document.querySelector('#alphaTab'));
|
|
39051
|
-
* api.playerFinished.on((args) => {
|
|
39052
|
-
* // speed trainer
|
|
39053
|
-
* api.playbackSpeed = Math.min(1.0, api.playbackSpeed + 0.1);
|
|
39054
|
-
* });
|
|
39055
|
-
* api.isLooping = true;
|
|
39056
|
-
* api.playbackSpeed = 0.5;
|
|
39057
|
-
* api.play()
|
|
39058
|
-
* ```
|
|
39059
|
-
*
|
|
39060
|
-
* @example
|
|
39061
|
-
* C#
|
|
39062
|
-
* ```cs
|
|
39063
|
-
* var api = new AlphaTabApi<MyControl>(...);
|
|
39064
|
-
* api.PlayerFinished.On(() =>
|
|
39065
|
-
* {
|
|
39066
|
-
* // speed trainer
|
|
39067
|
-
* api.PlaybackSpeed = Math.Min(1.0, api.PlaybackSpeed + 0.1);
|
|
39068
|
-
* });
|
|
39069
|
-
* api.IsLooping = true;
|
|
39070
|
-
* api.PlaybackSpeed = 0.5;
|
|
39071
|
-
* api.Play();
|
|
39072
|
-
* ```
|
|
39073
|
-
*
|
|
39074
|
-
* @example
|
|
39075
|
-
* Android
|
|
39076
|
-
* ```kotlin
|
|
39077
|
-
* val api = AlphaTabApi<MyControl>(...)
|
|
39078
|
-
* api.playerFinished.on {
|
|
39079
|
-
* // speed trainer
|
|
39080
|
-
* api.playbackSpeed = min(1.0, api.playbackSpeed + 0.1);
|
|
39081
|
-
* }
|
|
39082
|
-
* api.isLooping = true
|
|
39083
|
-
* api.playbackSpeed = 0.5
|
|
39084
|
-
* api.play()
|
|
39085
|
-
* ```
|
|
39086
|
-
*
|
|
39087
|
-
*/
|
|
39088
|
-
this.playerFinished = new EventEmitter();
|
|
39089
|
-
/**
|
|
39090
|
-
* This event is fired when the SoundFont needed for playback was loaded.
|
|
39091
|
-
*
|
|
39092
|
-
* @eventProperty
|
|
39093
|
-
* @category Events - Player
|
|
39094
|
-
* @since 0.9.4
|
|
39095
|
-
*
|
|
39096
|
-
* @example
|
|
39097
|
-
* JavaScript
|
|
39098
|
-
* ```js
|
|
39099
|
-
* const api = new alphaTab.AlphaTabApi(document.querySelector('#alphaTab'));
|
|
39100
|
-
* api.soundFontLoaded.on(() => {
|
|
39101
|
-
* hideSoundFontLoadingIndicator();
|
|
39102
|
-
* });
|
|
39103
|
-
* ```
|
|
39104
|
-
*
|
|
39105
|
-
* @example
|
|
39106
|
-
* C#
|
|
39107
|
-
* ```cs
|
|
39108
|
-
* var api = new AlphaTabApi<MyControl>(...);
|
|
39109
|
-
* api.SoundFontLoaded.On(() =>
|
|
39110
|
-
* {
|
|
39111
|
-
* HideSoundFontLoadingIndicator();
|
|
39112
|
-
* });
|
|
39113
|
-
* ```
|
|
39114
|
-
*
|
|
39115
|
-
* @example
|
|
39116
|
-
* Android
|
|
39117
|
-
* ```kotlin
|
|
39118
|
-
* val api = AlphaTabApi<MyControl>(...);
|
|
39119
|
-
* api.soundFontLoaded.on {
|
|
39120
|
-
* hideSoundFontLoadingIndicator();
|
|
39121
|
-
* }
|
|
39122
|
-
* ```
|
|
39123
|
-
*
|
|
39124
|
-
*/
|
|
39125
|
-
this.soundFontLoaded = new EventEmitter();
|
|
39126
39384
|
/**
|
|
39127
39385
|
* This event is fired when a Midi file is being loaded.
|
|
39128
39386
|
*
|
|
@@ -39211,176 +39469,18 @@
|
|
|
39211
39469
|
*/
|
|
39212
39470
|
this.midiLoaded = new EventEmitterOfT();
|
|
39213
39471
|
/**
|
|
39214
|
-
* This event is fired when
|
|
39215
|
-
*
|
|
39216
|
-
* @eventProperty
|
|
39217
|
-
* @category Events - Player
|
|
39218
|
-
* @since 0.9.4
|
|
39219
|
-
*
|
|
39220
|
-
* @example
|
|
39221
|
-
* JavaScript
|
|
39222
|
-
* ```js
|
|
39223
|
-
* const api = new alphaTab.AlphaTabApi(document.querySelector('#alphaTab'));
|
|
39224
|
-
* api.playerStateChanged.on((args) => {
|
|
39225
|
-
* updatePlayerControls(args.state, args.stopped);
|
|
39226
|
-
* });
|
|
39227
|
-
* ```
|
|
39228
|
-
*
|
|
39229
|
-
* @example
|
|
39230
|
-
* C#
|
|
39231
|
-
* ```cs
|
|
39232
|
-
* var api = new AlphaTabApi<MyControl>(...);
|
|
39233
|
-
* api.PlayerStateChanged.On(args =>
|
|
39234
|
-
* {
|
|
39235
|
-
* UpdatePlayerControls(args);
|
|
39236
|
-
* });
|
|
39237
|
-
* ```
|
|
39238
|
-
*
|
|
39239
|
-
* @example
|
|
39240
|
-
* Android
|
|
39241
|
-
* ```kotlin
|
|
39242
|
-
* val api = AlphaTabApi<MyControl>(...)
|
|
39243
|
-
* api.playerStateChanged.on { args ->
|
|
39244
|
-
* updatePlayerControls(args)
|
|
39245
|
-
* }
|
|
39246
|
-
* ```
|
|
39247
|
-
*
|
|
39248
|
-
*/
|
|
39249
|
-
this.playerStateChanged = new EventEmitterOfT();
|
|
39250
|
-
/**
|
|
39251
|
-
* This event is fired when the current playback position of the song changed.
|
|
39252
|
-
*
|
|
39253
|
-
* @eventProperty
|
|
39254
|
-
* @category Events - Player
|
|
39255
|
-
* @since 0.9.4
|
|
39256
|
-
*
|
|
39257
|
-
* @example
|
|
39258
|
-
* JavaScript
|
|
39259
|
-
* ```js
|
|
39260
|
-
* const api = new alphaTab.AlphaTabApi(document.querySelector('#alphaTab'));
|
|
39261
|
-
* api.playerPositionChanged.on((args) => {
|
|
39262
|
-
* updatePlayerPosition(args);
|
|
39263
|
-
* });
|
|
39264
|
-
* ```
|
|
39265
|
-
*
|
|
39266
|
-
* @example
|
|
39267
|
-
* C#
|
|
39268
|
-
* ```cs
|
|
39269
|
-
* var api = new AlphaTabApi<MyControl>(...);
|
|
39270
|
-
* api.PlayerPositionChanged.On(args =>
|
|
39271
|
-
* {
|
|
39272
|
-
* UpdatePlayerPosition(args);
|
|
39273
|
-
* });
|
|
39274
|
-
* ```
|
|
39275
|
-
*
|
|
39276
|
-
* @example
|
|
39277
|
-
* Android
|
|
39278
|
-
* ```kotlin
|
|
39279
|
-
* val api = AlphaTabApi<MyControl>(...)
|
|
39280
|
-
* api.playerPositionChanged.on { args ->
|
|
39281
|
-
* updatePlayerPosition(args)
|
|
39282
|
-
* }
|
|
39283
|
-
* ```
|
|
39284
|
-
*
|
|
39285
|
-
*/
|
|
39286
|
-
this.playerPositionChanged = new EventEmitterOfT();
|
|
39287
|
-
/**
|
|
39288
|
-
* This event is fired when the synthesizer played certain midi events.
|
|
39289
|
-
*
|
|
39290
|
-
* @remarks
|
|
39291
|
-
* This event is fired when the synthesizer played certain midi events. This allows reacing on various low level
|
|
39292
|
-
* audio playback elements like notes/rests played or metronome ticks.
|
|
39293
|
-
*
|
|
39294
|
-
* Refer to the [related guide](https://www.alphatab.net/docs/guides/handling-midi-events) to learn more about this feature.
|
|
39295
|
-
*
|
|
39296
|
-
* Also note that the provided data models changed significantly in {@version 1.3.0}. We try to provide backwards compatibility
|
|
39297
|
-
* until some extend but highly encourage changing to the new models in case of problems.
|
|
39472
|
+
* This event is fired when a settings update was requested.
|
|
39298
39473
|
*
|
|
39299
39474
|
* @eventProperty
|
|
39300
|
-
* @category Events -
|
|
39301
|
-
* @since 1.
|
|
39302
|
-
*
|
|
39303
|
-
* @example
|
|
39304
|
-
* JavaScript
|
|
39305
|
-
* ```js
|
|
39306
|
-
* const api = new alphaTab.AlphaTabApi(document.querySelector('#alphaTab'));
|
|
39307
|
-
* api.midiEventsPlayedFilter = [alphaTab.midi.MidiEventType.AlphaTabMetronome];
|
|
39308
|
-
* api.midiEventsPlayed.on(function(e) {
|
|
39309
|
-
* for(const midi of e.events) {
|
|
39310
|
-
* if(midi.isMetronome) {
|
|
39311
|
-
* console.log('Metronome tick ' + midi.tick);
|
|
39312
|
-
* }
|
|
39313
|
-
* }
|
|
39314
|
-
* });
|
|
39315
|
-
* ```
|
|
39316
|
-
*
|
|
39317
|
-
* @example
|
|
39318
|
-
* C#
|
|
39319
|
-
* ```cs
|
|
39320
|
-
* var api = new AlphaTabApi<MyControl>(...);
|
|
39321
|
-
* api.MidiEventsPlayedFilter = new MidiEventType[] { AlphaTab.Midi.MidiEventType.AlphaTabMetronome };
|
|
39322
|
-
* api.MidiEventsPlayed.On(e =>
|
|
39323
|
-
* {
|
|
39324
|
-
* foreach(var midi of e.events)
|
|
39325
|
-
* {
|
|
39326
|
-
* if(midi is AlphaTab.Midi.AlphaTabMetronomeEvent sysex && sysex.IsMetronome)
|
|
39327
|
-
* {
|
|
39328
|
-
* Console.WriteLine("Metronome tick " + midi.Tick);
|
|
39329
|
-
* }
|
|
39330
|
-
* }
|
|
39331
|
-
* });
|
|
39332
|
-
* ```
|
|
39333
|
-
*
|
|
39334
|
-
* @example
|
|
39335
|
-
* Android
|
|
39336
|
-
* ```kotlin
|
|
39337
|
-
* val api = AlphaTabApi<MyControl>(...);
|
|
39338
|
-
* api.midiEventsPlayedFilter = alphaTab.collections.List<alphaTab.midi.MidiEventType>( alphaTab.midi.MidiEventType.AlphaTabMetronome )
|
|
39339
|
-
* api.midiEventsPlayed.on { e ->
|
|
39340
|
-
* for (midi in e.events) {
|
|
39341
|
-
* if(midi instanceof alphaTab.midi.AlphaTabMetronomeEvent && midi.isMetronome) {
|
|
39342
|
-
* println("Metronome tick " + midi.tick);
|
|
39343
|
-
* }
|
|
39344
|
-
* }
|
|
39345
|
-
* }
|
|
39346
|
-
* ```
|
|
39347
|
-
* @see {@link MidiEvent}
|
|
39348
|
-
* @see {@link TimeSignatureEvent}
|
|
39349
|
-
* @see {@link AlphaTabMetronomeEvent}
|
|
39350
|
-
* @see {@link AlphaTabRestEvent}
|
|
39351
|
-
* @see {@link NoteOnEvent}
|
|
39352
|
-
* @see {@link NoteOffEvent}
|
|
39353
|
-
* @see {@link ControlChangeEvent}
|
|
39354
|
-
* @see {@link ProgramChangeEvent}
|
|
39355
|
-
* @see {@link TempoChangeEvent}
|
|
39356
|
-
* @see {@link PitchBendEvent}
|
|
39357
|
-
* @see {@link NoteBendEvent}
|
|
39358
|
-
* @see {@link EndOfTrackEvent}
|
|
39359
|
-
* @see {@link MetaEvent}
|
|
39360
|
-
* @see {@link MetaDataEvent}
|
|
39361
|
-
* @see {@link MetaNumberEvent}
|
|
39362
|
-
* @see {@link Midi20PerNotePitchBendEvent}
|
|
39363
|
-
* @see {@link SystemCommonEvent}
|
|
39364
|
-
* @see {@link SystemExclusiveEvent}
|
|
39365
|
-
*/
|
|
39366
|
-
this.midiEventsPlayed = new EventEmitterOfT();
|
|
39367
|
-
/**
|
|
39368
|
-
* This event is fired when the playback range changed.
|
|
39369
|
-
*
|
|
39370
|
-
* @eventProperty
|
|
39371
|
-
* @category Events - Player
|
|
39372
|
-
* @since 1.2.3
|
|
39475
|
+
* @category Events - Core
|
|
39476
|
+
* @since 1.6.0
|
|
39373
39477
|
*
|
|
39374
39478
|
* @example
|
|
39375
39479
|
* JavaScript
|
|
39376
39480
|
* ```js
|
|
39377
39481
|
* const api = new alphaTab.AlphaTabApi(document.querySelector('#alphaTab'));
|
|
39378
|
-
* api.
|
|
39379
|
-
*
|
|
39380
|
-
* highlightRangeInProgressBar(args.playbackRange.startTick, args.playbackRange.endTick);
|
|
39381
|
-
* } else {
|
|
39382
|
-
* clearHighlightInProgressBar();
|
|
39383
|
-
* }
|
|
39482
|
+
* api.settingsUpdated.on(() => {
|
|
39483
|
+
* updateSettingsUI(api.settings);
|
|
39384
39484
|
* });
|
|
39385
39485
|
* ```
|
|
39386
39486
|
*
|
|
@@ -39388,16 +39488,9 @@
|
|
|
39388
39488
|
* C#
|
|
39389
39489
|
* ```cs
|
|
39390
39490
|
* var api = new AlphaTabApi<MyControl>(...);
|
|
39391
|
-
* api.
|
|
39491
|
+
* api.SettingsUpdated.On(() =>
|
|
39392
39492
|
* {
|
|
39393
|
-
*
|
|
39394
|
-
* {
|
|
39395
|
-
* HighlightRangeInProgressBar(args.PlaybackRange.StartTick, args.PlaybackRange.EndTick);
|
|
39396
|
-
* }
|
|
39397
|
-
* else
|
|
39398
|
-
* {
|
|
39399
|
-
* ClearHighlightInProgressBar();
|
|
39400
|
-
* }
|
|
39493
|
+
* UpdateSettingsUI(api.settings);
|
|
39401
39494
|
* });
|
|
39402
39495
|
* ```
|
|
39403
39496
|
*
|
|
@@ -39405,21 +39498,12 @@
|
|
|
39405
39498
|
* Android
|
|
39406
39499
|
* ```kotlin
|
|
39407
39500
|
* val api = AlphaTabApi<MyControl>(...)
|
|
39408
|
-
* api.
|
|
39409
|
-
*
|
|
39410
|
-
* if (playbackRange != null) {
|
|
39411
|
-
* highlightRangeInProgressBar(playbackRange.startTick, playbackRange.endTick)
|
|
39412
|
-
* } else {
|
|
39413
|
-
* clearHighlightInProgressBar()
|
|
39414
|
-
* }
|
|
39501
|
+
* api.SettingsUpdated.on {
|
|
39502
|
+
* updateSettingsUI(api.settings)
|
|
39415
39503
|
* }
|
|
39416
39504
|
* ```
|
|
39417
39505
|
*
|
|
39418
39506
|
*/
|
|
39419
|
-
this.playbackRangeChanged = new EventEmitterOfT();
|
|
39420
|
-
/**
|
|
39421
|
-
* @internal
|
|
39422
|
-
*/
|
|
39423
39507
|
this.settingsUpdated = new EventEmitter();
|
|
39424
39508
|
this.uiFacade = uiFacade;
|
|
39425
39509
|
this.container = uiFacade.rootContainer;
|
|
@@ -39432,48 +39516,49 @@
|
|
|
39432
39516
|
Environment.printEnvironmentInfo(false);
|
|
39433
39517
|
this.canvasElement = uiFacade.createCanvasElement();
|
|
39434
39518
|
this.container.appendChild(this.canvasElement);
|
|
39519
|
+
this._renderer = new ScoreRendererWrapper();
|
|
39435
39520
|
if (this.settings.core.useWorkers &&
|
|
39436
39521
|
this.uiFacade.areWorkersSupported &&
|
|
39437
39522
|
Environment.getRenderEngineFactory(this.settings.core.engine).supportsWorkers) {
|
|
39438
|
-
this.
|
|
39523
|
+
this._renderer.instance = this.uiFacade.createWorkerRenderer();
|
|
39439
39524
|
}
|
|
39440
39525
|
else {
|
|
39441
|
-
this.
|
|
39526
|
+
this._renderer.instance = new ScoreRenderer(this.settings);
|
|
39442
39527
|
}
|
|
39443
39528
|
this.container.resize.on(Environment.throttle(() => {
|
|
39444
39529
|
if (this._isDestroyed) {
|
|
39445
39530
|
return;
|
|
39446
39531
|
}
|
|
39447
|
-
if (this.container.width !== this.
|
|
39532
|
+
if (this.container.width !== this._renderer.width) {
|
|
39448
39533
|
this.triggerResize();
|
|
39449
39534
|
}
|
|
39450
39535
|
}, uiFacade.resizeThrottle));
|
|
39451
39536
|
const initialResizeEventInfo = new ResizeEventArgs();
|
|
39452
|
-
initialResizeEventInfo.oldWidth = this.
|
|
39537
|
+
initialResizeEventInfo.oldWidth = this._renderer.width;
|
|
39453
39538
|
initialResizeEventInfo.newWidth = this.container.width | 0;
|
|
39454
39539
|
initialResizeEventInfo.settings = this.settings;
|
|
39455
39540
|
this.onResize(initialResizeEventInfo);
|
|
39456
|
-
this.
|
|
39457
|
-
this.
|
|
39541
|
+
this._renderer.preRender.on(this.onRenderStarted.bind(this));
|
|
39542
|
+
this._renderer.renderFinished.on(renderingResult => {
|
|
39458
39543
|
this.onRenderFinished(renderingResult);
|
|
39459
39544
|
});
|
|
39460
|
-
this.
|
|
39545
|
+
this._renderer.postRenderFinished.on(() => {
|
|
39461
39546
|
const duration = Date.now() - this._startTime;
|
|
39462
39547
|
Logger.debug('rendering', `Rendering completed in ${duration}ms`);
|
|
39463
39548
|
this.onPostRenderFinished();
|
|
39464
39549
|
});
|
|
39465
|
-
this.
|
|
39550
|
+
this._renderer.preRender.on(_ => {
|
|
39466
39551
|
this._startTime = Date.now();
|
|
39467
39552
|
});
|
|
39468
|
-
this.
|
|
39469
|
-
this.
|
|
39470
|
-
this.
|
|
39471
|
-
this.appendRenderResult(r);
|
|
39472
|
-
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);
|
|
39473
39557
|
});
|
|
39474
|
-
this.
|
|
39558
|
+
this._renderer.error.on(this.onError.bind(this));
|
|
39559
|
+
this.setupPlayerWrapper();
|
|
39475
39560
|
if (this.settings.player.playerMode !== exports.PlayerMode.Disabled) {
|
|
39476
|
-
this.
|
|
39561
|
+
this.setupOrDestroyPlayer();
|
|
39477
39562
|
}
|
|
39478
39563
|
this.setupClickHandling();
|
|
39479
39564
|
// delay rendering to allow ui to hook up with events first.
|
|
@@ -39481,6 +39566,36 @@
|
|
|
39481
39566
|
this.uiFacade.initialRender();
|
|
39482
39567
|
});
|
|
39483
39568
|
}
|
|
39569
|
+
setupPlayerWrapper() {
|
|
39570
|
+
const player = new AlphaSynthWrapper();
|
|
39571
|
+
this._player = player;
|
|
39572
|
+
player.ready.on(() => {
|
|
39573
|
+
this.loadMidiForScore();
|
|
39574
|
+
});
|
|
39575
|
+
player.readyForPlayback.on(() => {
|
|
39576
|
+
this.onPlayerReady();
|
|
39577
|
+
if (this.tracks) {
|
|
39578
|
+
for (const track of this.tracks) {
|
|
39579
|
+
const volume = track.playbackInfo.volume / 16;
|
|
39580
|
+
player.setChannelVolume(track.playbackInfo.primaryChannel, volume);
|
|
39581
|
+
player.setChannelVolume(track.playbackInfo.secondaryChannel, volume);
|
|
39582
|
+
}
|
|
39583
|
+
}
|
|
39584
|
+
});
|
|
39585
|
+
player.soundFontLoaded.on(this.onSoundFontLoaded.bind(this));
|
|
39586
|
+
player.soundFontLoadFailed.on(e => {
|
|
39587
|
+
this.onError(e);
|
|
39588
|
+
});
|
|
39589
|
+
player.midiLoaded.on(this.onMidiLoaded.bind(this));
|
|
39590
|
+
player.midiLoadFailed.on(e => {
|
|
39591
|
+
this.onError(e);
|
|
39592
|
+
});
|
|
39593
|
+
player.stateChanged.on(this.onPlayerStateChanged.bind(this));
|
|
39594
|
+
player.positionChanged.on(this.onPlayerPositionChanged.bind(this));
|
|
39595
|
+
player.midiEventsPlayed.on(this.onMidiEventsPlayed.bind(this));
|
|
39596
|
+
player.playbackRangeChanged.on(this.onPlaybackRangeChanged.bind(this));
|
|
39597
|
+
player.finished.on(this.onPlayerFinished.bind(this));
|
|
39598
|
+
}
|
|
39484
39599
|
/**
|
|
39485
39600
|
* Destroys the alphaTab control and restores the initial state of the UI.
|
|
39486
39601
|
* @remarks
|
|
@@ -39513,11 +39628,9 @@
|
|
|
39513
39628
|
*/
|
|
39514
39629
|
destroy() {
|
|
39515
39630
|
this._isDestroyed = true;
|
|
39516
|
-
|
|
39517
|
-
this.player.destroy();
|
|
39518
|
-
}
|
|
39631
|
+
this._player.destroy();
|
|
39519
39632
|
this.uiFacade.destroy();
|
|
39520
|
-
this.
|
|
39633
|
+
this._renderer.destroy();
|
|
39521
39634
|
}
|
|
39522
39635
|
/**
|
|
39523
39636
|
* Applies any changes that were done to the settings object.
|
|
@@ -39562,17 +39675,29 @@
|
|
|
39562
39675
|
if (score) {
|
|
39563
39676
|
ModelUtils.applyPitchOffsets(this.settings, score);
|
|
39564
39677
|
}
|
|
39565
|
-
this.
|
|
39566
|
-
|
|
39567
|
-
|
|
39568
|
-
|
|
39569
|
-
|
|
39678
|
+
this.updateRenderer();
|
|
39679
|
+
this._renderer.updateSettings(this.settings);
|
|
39680
|
+
this.setupOrDestroyPlayer();
|
|
39681
|
+
this.onSettingsUpdated();
|
|
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();
|
|
39570
39692
|
}
|
|
39571
39693
|
}
|
|
39572
39694
|
else {
|
|
39573
|
-
|
|
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
|
+
}
|
|
39574
39700
|
}
|
|
39575
|
-
this.onSettingsUpdated();
|
|
39576
39701
|
}
|
|
39577
39702
|
/**
|
|
39578
39703
|
* Initiates a load of the score using the given data.
|
|
@@ -39768,30 +39893,33 @@
|
|
|
39768
39893
|
}
|
|
39769
39894
|
else {
|
|
39770
39895
|
const resizeEventInfo = new ResizeEventArgs();
|
|
39771
|
-
resizeEventInfo.oldWidth = this.
|
|
39896
|
+
resizeEventInfo.oldWidth = this._renderer.width;
|
|
39772
39897
|
resizeEventInfo.newWidth = this.container.width;
|
|
39773
39898
|
resizeEventInfo.settings = this.settings;
|
|
39774
39899
|
this.onResize(resizeEventInfo);
|
|
39775
|
-
this.
|
|
39776
|
-
this.
|
|
39777
|
-
this.
|
|
39900
|
+
this._renderer.updateSettings(this.settings);
|
|
39901
|
+
this._renderer.width = this.container.width;
|
|
39902
|
+
this._renderer.resizeRender();
|
|
39778
39903
|
}
|
|
39779
39904
|
}
|
|
39780
|
-
appendRenderResult(result) {
|
|
39781
|
-
|
|
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) {
|
|
39782
39910
|
this.canvasElement.width = result.totalWidth;
|
|
39783
39911
|
this.canvasElement.height = result.totalHeight;
|
|
39784
39912
|
if (this._cursorWrapper) {
|
|
39785
39913
|
this._cursorWrapper.width = result.totalWidth;
|
|
39786
39914
|
this._cursorWrapper.height = result.totalHeight;
|
|
39787
39915
|
}
|
|
39788
|
-
if (result.width > 0 || result.height > 0) {
|
|
39789
|
-
this.uiFacade.beginAppendRenderResults(result);
|
|
39790
|
-
}
|
|
39791
39916
|
}
|
|
39792
|
-
|
|
39917
|
+
if (result.width > 0 || result.height > 0) {
|
|
39793
39918
|
this.uiFacade.beginAppendRenderResults(result);
|
|
39794
39919
|
}
|
|
39920
|
+
if (isLast) {
|
|
39921
|
+
this.uiFacade.beginAppendRenderResults(null);
|
|
39922
|
+
}
|
|
39795
39923
|
}
|
|
39796
39924
|
updateRenderResult(result) {
|
|
39797
39925
|
if (result && result.renderResult) {
|
|
@@ -39877,9 +40005,6 @@
|
|
|
39877
40005
|
* ```
|
|
39878
40006
|
*/
|
|
39879
40007
|
loadSoundFont(data, append = false) {
|
|
39880
|
-
if (!this.player) {
|
|
39881
|
-
return false;
|
|
39882
|
-
}
|
|
39883
40008
|
return this.uiFacade.loadSoundFont(data, append);
|
|
39884
40009
|
}
|
|
39885
40010
|
/**
|
|
@@ -39925,10 +40050,7 @@
|
|
|
39925
40050
|
* ```
|
|
39926
40051
|
*/
|
|
39927
40052
|
resetSoundFonts() {
|
|
39928
|
-
|
|
39929
|
-
return;
|
|
39930
|
-
}
|
|
39931
|
-
this.player.resetSoundFonts();
|
|
40053
|
+
this._player.resetSoundFonts();
|
|
39932
40054
|
}
|
|
39933
40055
|
/**
|
|
39934
40056
|
* Initiates a re-rendering of the current setup.
|
|
@@ -39959,13 +40081,10 @@
|
|
|
39959
40081
|
* ```
|
|
39960
40082
|
*/
|
|
39961
40083
|
render() {
|
|
39962
|
-
if (!this.renderer) {
|
|
39963
|
-
return;
|
|
39964
|
-
}
|
|
39965
40084
|
if (this.uiFacade.canRender) {
|
|
39966
40085
|
// when font is finally loaded, start rendering
|
|
39967
|
-
this.
|
|
39968
|
-
this.
|
|
40086
|
+
this._renderer.width = this.container.width;
|
|
40087
|
+
this._renderer.renderScore(this.score, this._trackIndexes);
|
|
39969
40088
|
}
|
|
39970
40089
|
else {
|
|
39971
40090
|
this.uiFacade.canRenderChanged.on(() => this.render());
|
|
@@ -40040,7 +40159,38 @@
|
|
|
40040
40159
|
* @since 1.5.0
|
|
40041
40160
|
*/
|
|
40042
40161
|
get boundsLookup() {
|
|
40043
|
-
return this.
|
|
40162
|
+
return this._renderer.boundsLookup;
|
|
40163
|
+
}
|
|
40164
|
+
/**
|
|
40165
|
+
* The alphaSynth player used for playback.
|
|
40166
|
+
* @remarks
|
|
40167
|
+
* This is the low-level API to the Midi synthesizer used for playback.
|
|
40168
|
+
* Gets access to the underling {@link IAlphaSynth} that is used for the audio playback.
|
|
40169
|
+
* @category Properties - Player
|
|
40170
|
+
* @since 0.9.4
|
|
40171
|
+
* @example
|
|
40172
|
+
* JavaScript
|
|
40173
|
+
* ```js
|
|
40174
|
+
* const api = new alphaTab.AlphaTabApi(document.querySelector('#alphaTab'));
|
|
40175
|
+
* setupPlayerEvents(api.settings);
|
|
40176
|
+
* ```
|
|
40177
|
+
*
|
|
40178
|
+
* @example
|
|
40179
|
+
* C#
|
|
40180
|
+
* ```cs
|
|
40181
|
+
* var api = new AlphaTabApi<MyControl>(...);
|
|
40182
|
+
* SetupPlayerEvents(api.Player);
|
|
40183
|
+
* ```
|
|
40184
|
+
*
|
|
40185
|
+
* @example
|
|
40186
|
+
* Android
|
|
40187
|
+
* ```kotlin
|
|
40188
|
+
* val api = AlphaTabApi<MyControl>(...)
|
|
40189
|
+
* setupPlayerEvents(api.player)
|
|
40190
|
+
* ```
|
|
40191
|
+
*/
|
|
40192
|
+
get player() {
|
|
40193
|
+
return this._player.instance ? this._player : null;
|
|
40044
40194
|
}
|
|
40045
40195
|
/**
|
|
40046
40196
|
* Whether the player is ready for starting the playback.
|
|
@@ -40071,10 +40221,7 @@
|
|
|
40071
40221
|
* ```
|
|
40072
40222
|
*/
|
|
40073
40223
|
get isReadyForPlayback() {
|
|
40074
|
-
|
|
40075
|
-
return false;
|
|
40076
|
-
}
|
|
40077
|
-
return this.player.isReadyForPlayback;
|
|
40224
|
+
return this._player.isReadyForPlayback;
|
|
40078
40225
|
}
|
|
40079
40226
|
/**
|
|
40080
40227
|
* The current player state.
|
|
@@ -40104,10 +40251,7 @@
|
|
|
40104
40251
|
* ```
|
|
40105
40252
|
*/
|
|
40106
40253
|
get playerState() {
|
|
40107
|
-
|
|
40108
|
-
return PlayerState.Paused;
|
|
40109
|
-
}
|
|
40110
|
-
return this.player.state;
|
|
40254
|
+
return this._player.state;
|
|
40111
40255
|
}
|
|
40112
40256
|
/**
|
|
40113
40257
|
* The current master volume as percentage (0-1).
|
|
@@ -40137,15 +40281,10 @@
|
|
|
40137
40281
|
* ```
|
|
40138
40282
|
*/
|
|
40139
40283
|
get masterVolume() {
|
|
40140
|
-
|
|
40141
|
-
return 0;
|
|
40142
|
-
}
|
|
40143
|
-
return this.player.masterVolume;
|
|
40284
|
+
return this._player.masterVolume;
|
|
40144
40285
|
}
|
|
40145
40286
|
set masterVolume(value) {
|
|
40146
|
-
|
|
40147
|
-
this.player.masterVolume = value;
|
|
40148
|
-
}
|
|
40287
|
+
this._player.masterVolume = value;
|
|
40149
40288
|
}
|
|
40150
40289
|
/**
|
|
40151
40290
|
* The metronome volume as percentage (0-1).
|
|
@@ -40176,15 +40315,10 @@
|
|
|
40176
40315
|
* ```
|
|
40177
40316
|
*/
|
|
40178
40317
|
get metronomeVolume() {
|
|
40179
|
-
|
|
40180
|
-
return 0;
|
|
40181
|
-
}
|
|
40182
|
-
return this.player.metronomeVolume;
|
|
40318
|
+
return this._player.metronomeVolume;
|
|
40183
40319
|
}
|
|
40184
40320
|
set metronomeVolume(value) {
|
|
40185
|
-
|
|
40186
|
-
this.player.metronomeVolume = value;
|
|
40187
|
-
}
|
|
40321
|
+
this._player.metronomeVolume = value;
|
|
40188
40322
|
}
|
|
40189
40323
|
/**
|
|
40190
40324
|
* The volume of the count-in metronome ticks.
|
|
@@ -40215,15 +40349,10 @@
|
|
|
40215
40349
|
* ```
|
|
40216
40350
|
*/
|
|
40217
40351
|
get countInVolume() {
|
|
40218
|
-
|
|
40219
|
-
return 0;
|
|
40220
|
-
}
|
|
40221
|
-
return this.player.countInVolume;
|
|
40352
|
+
return this._player.countInVolume;
|
|
40222
40353
|
}
|
|
40223
40354
|
set countInVolume(value) {
|
|
40224
|
-
|
|
40225
|
-
this.player.countInVolume = value;
|
|
40226
|
-
}
|
|
40355
|
+
this._player.countInVolume = value;
|
|
40227
40356
|
}
|
|
40228
40357
|
/**
|
|
40229
40358
|
* The midi events which will trigger the `midiEventsPlayed` event
|
|
@@ -40282,15 +40411,10 @@
|
|
|
40282
40411
|
* ```
|
|
40283
40412
|
*/
|
|
40284
40413
|
get midiEventsPlayedFilter() {
|
|
40285
|
-
|
|
40286
|
-
return [];
|
|
40287
|
-
}
|
|
40288
|
-
return this.player.midiEventsPlayedFilter;
|
|
40414
|
+
return this._player.midiEventsPlayedFilter;
|
|
40289
40415
|
}
|
|
40290
40416
|
set midiEventsPlayedFilter(value) {
|
|
40291
|
-
|
|
40292
|
-
this.player.midiEventsPlayedFilter = value;
|
|
40293
|
-
}
|
|
40417
|
+
this._player.midiEventsPlayedFilter = value;
|
|
40294
40418
|
}
|
|
40295
40419
|
/**
|
|
40296
40420
|
* The position within the song in midi ticks.
|
|
@@ -40318,15 +40442,10 @@
|
|
|
40318
40442
|
* ```
|
|
40319
40443
|
*/
|
|
40320
40444
|
get tickPosition() {
|
|
40321
|
-
|
|
40322
|
-
return 0;
|
|
40323
|
-
}
|
|
40324
|
-
return this.player.tickPosition;
|
|
40445
|
+
return this._player.tickPosition;
|
|
40325
40446
|
}
|
|
40326
40447
|
set tickPosition(value) {
|
|
40327
|
-
|
|
40328
|
-
this.player.tickPosition = value;
|
|
40329
|
-
}
|
|
40448
|
+
this._player.tickPosition = value;
|
|
40330
40449
|
}
|
|
40331
40450
|
/**
|
|
40332
40451
|
* The position within the song in milliseconds
|
|
@@ -40354,15 +40473,10 @@
|
|
|
40354
40473
|
* ```
|
|
40355
40474
|
*/
|
|
40356
40475
|
get timePosition() {
|
|
40357
|
-
|
|
40358
|
-
return 0;
|
|
40359
|
-
}
|
|
40360
|
-
return this.player.timePosition;
|
|
40476
|
+
return this._player.timePosition;
|
|
40361
40477
|
}
|
|
40362
40478
|
set timePosition(value) {
|
|
40363
|
-
|
|
40364
|
-
this.player.timePosition = value;
|
|
40365
|
-
}
|
|
40479
|
+
this._player.timePosition = value;
|
|
40366
40480
|
}
|
|
40367
40481
|
/**
|
|
40368
40482
|
* The range of the song that should be played.
|
|
@@ -40396,17 +40510,12 @@
|
|
|
40396
40510
|
* ```
|
|
40397
40511
|
*/
|
|
40398
40512
|
get playbackRange() {
|
|
40399
|
-
|
|
40400
|
-
return null;
|
|
40401
|
-
}
|
|
40402
|
-
return this.player.playbackRange;
|
|
40513
|
+
return this._player.playbackRange;
|
|
40403
40514
|
}
|
|
40404
40515
|
set playbackRange(value) {
|
|
40405
|
-
|
|
40406
|
-
|
|
40407
|
-
|
|
40408
|
-
this.updateSelectionCursor(value);
|
|
40409
|
-
}
|
|
40516
|
+
this._player.playbackRange = value;
|
|
40517
|
+
if (this.settings.player.enableCursor) {
|
|
40518
|
+
this.updateSelectionCursor(value);
|
|
40410
40519
|
}
|
|
40411
40520
|
}
|
|
40412
40521
|
/**
|
|
@@ -40438,15 +40547,10 @@
|
|
|
40438
40547
|
* ```
|
|
40439
40548
|
*/
|
|
40440
40549
|
get playbackSpeed() {
|
|
40441
|
-
|
|
40442
|
-
return 0;
|
|
40443
|
-
}
|
|
40444
|
-
return this.player.playbackSpeed;
|
|
40550
|
+
return this._player.playbackSpeed;
|
|
40445
40551
|
}
|
|
40446
40552
|
set playbackSpeed(value) {
|
|
40447
|
-
|
|
40448
|
-
this.player.playbackSpeed = value;
|
|
40449
|
-
}
|
|
40553
|
+
this._player.playbackSpeed = value;
|
|
40450
40554
|
}
|
|
40451
40555
|
/**
|
|
40452
40556
|
* Whether the playback should automatically restart after it finished.
|
|
@@ -40477,27 +40581,21 @@
|
|
|
40477
40581
|
* ```
|
|
40478
40582
|
*/
|
|
40479
40583
|
get isLooping() {
|
|
40480
|
-
|
|
40481
|
-
return false;
|
|
40482
|
-
}
|
|
40483
|
-
return this.player.isLooping;
|
|
40584
|
+
return this._player.isLooping;
|
|
40484
40585
|
}
|
|
40485
40586
|
set isLooping(value) {
|
|
40486
|
-
|
|
40487
|
-
this.player.isLooping = value;
|
|
40488
|
-
}
|
|
40587
|
+
this._player.isLooping = value;
|
|
40489
40588
|
}
|
|
40490
40589
|
destroyPlayer() {
|
|
40491
|
-
|
|
40492
|
-
return;
|
|
40493
|
-
}
|
|
40494
|
-
this.player.destroy();
|
|
40495
|
-
this.player = null;
|
|
40590
|
+
this._player.destroy();
|
|
40496
40591
|
this._previousTick = 0;
|
|
40497
|
-
this._playerState = PlayerState.Paused;
|
|
40498
40592
|
this.destroyCursors();
|
|
40499
40593
|
}
|
|
40500
|
-
|
|
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
|
+
*/
|
|
40598
|
+
setupOrDestroyPlayer() {
|
|
40501
40599
|
let mode = this.settings.player.playerMode;
|
|
40502
40600
|
if (mode === exports.PlayerMode.EnabledAutomatic) {
|
|
40503
40601
|
const score = this.score;
|
|
@@ -40511,68 +40609,44 @@
|
|
|
40511
40609
|
mode = exports.PlayerMode.EnabledSynthesizer;
|
|
40512
40610
|
}
|
|
40513
40611
|
}
|
|
40612
|
+
let newPlayer = null;
|
|
40514
40613
|
if (mode !== this._actualPlayerMode) {
|
|
40515
40614
|
this.destroyPlayer();
|
|
40615
|
+
this.updateCursors();
|
|
40616
|
+
switch (mode) {
|
|
40617
|
+
case exports.PlayerMode.Disabled:
|
|
40618
|
+
newPlayer = null;
|
|
40619
|
+
break;
|
|
40620
|
+
case exports.PlayerMode.EnabledSynthesizer:
|
|
40621
|
+
newPlayer = this.uiFacade.createWorkerPlayer();
|
|
40622
|
+
break;
|
|
40623
|
+
case exports.PlayerMode.EnabledBackingTrack:
|
|
40624
|
+
newPlayer = this.uiFacade.createBackingTrackPlayer();
|
|
40625
|
+
break;
|
|
40626
|
+
case exports.PlayerMode.EnabledExternalMedia:
|
|
40627
|
+
newPlayer = new ExternalMediaPlayer(this.settings.player.bufferTimeInMilliseconds);
|
|
40628
|
+
break;
|
|
40629
|
+
}
|
|
40516
40630
|
}
|
|
40517
|
-
|
|
40518
|
-
|
|
40519
|
-
|
|
40520
|
-
|
|
40521
|
-
this.destroyPlayer();
|
|
40522
|
-
return false;
|
|
40523
|
-
case exports.PlayerMode.EnabledSynthesizer:
|
|
40524
|
-
if (this.player) {
|
|
40525
|
-
return true;
|
|
40526
|
-
}
|
|
40527
|
-
// new player needed
|
|
40528
|
-
this.player = this.uiFacade.createWorkerPlayer();
|
|
40529
|
-
break;
|
|
40530
|
-
case exports.PlayerMode.EnabledBackingTrack:
|
|
40531
|
-
if (this.player) {
|
|
40532
|
-
return true;
|
|
40533
|
-
}
|
|
40534
|
-
// new player needed
|
|
40535
|
-
this.player = this.uiFacade.createBackingTrackPlayer();
|
|
40536
|
-
break;
|
|
40537
|
-
case exports.PlayerMode.EnabledExternalMedia:
|
|
40538
|
-
if (this.player) {
|
|
40539
|
-
return true;
|
|
40540
|
-
}
|
|
40541
|
-
this.player = new ExternalMediaPlayer(this.settings.player.bufferTimeInMilliseconds);
|
|
40542
|
-
break;
|
|
40631
|
+
else {
|
|
40632
|
+
// no change in player mode, just update song info if needed
|
|
40633
|
+
this.updateCursors();
|
|
40634
|
+
return false;
|
|
40543
40635
|
}
|
|
40544
|
-
|
|
40636
|
+
this._actualPlayerMode = mode;
|
|
40637
|
+
if (!newPlayer) {
|
|
40545
40638
|
return false;
|
|
40546
40639
|
}
|
|
40547
|
-
this.
|
|
40548
|
-
this.loadMidiForScore();
|
|
40549
|
-
});
|
|
40550
|
-
this.player.readyForPlayback.on(() => {
|
|
40551
|
-
this.onPlayerReady();
|
|
40552
|
-
if (this.tracks) {
|
|
40553
|
-
for (const track of this.tracks) {
|
|
40554
|
-
const volume = track.playbackInfo.volume / 16;
|
|
40555
|
-
this.player.setChannelVolume(track.playbackInfo.primaryChannel, volume);
|
|
40556
|
-
this.player.setChannelVolume(track.playbackInfo.secondaryChannel, volume);
|
|
40557
|
-
}
|
|
40558
|
-
}
|
|
40559
|
-
});
|
|
40560
|
-
this.player.soundFontLoaded.on(this.onSoundFontLoaded.bind(this));
|
|
40561
|
-
this.player.soundFontLoadFailed.on(e => {
|
|
40562
|
-
this.onError(e);
|
|
40563
|
-
});
|
|
40564
|
-
this.player.midiLoaded.on(this.onMidiLoaded.bind(this));
|
|
40565
|
-
this.player.midiLoadFailed.on(e => {
|
|
40566
|
-
this.onError(e);
|
|
40567
|
-
});
|
|
40568
|
-
this.player.stateChanged.on(this.onPlayerStateChanged.bind(this));
|
|
40569
|
-
this.player.positionChanged.on(this.onPlayerPositionChanged.bind(this));
|
|
40570
|
-
this.player.midiEventsPlayed.on(this.onMidiEventsPlayed.bind(this));
|
|
40571
|
-
this.player.playbackRangeChanged.on(this.onPlaybackRangeChanged.bind(this));
|
|
40572
|
-
this.player.finished.on(this.onPlayerFinished.bind(this));
|
|
40573
|
-
this.setupPlayerEvents();
|
|
40640
|
+
this._player.instance = newPlayer;
|
|
40574
40641
|
return false;
|
|
40575
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
|
+
*/
|
|
40576
40650
|
loadMidiForScore() {
|
|
40577
40651
|
if (!this.score) {
|
|
40578
40652
|
return;
|
|
@@ -40590,12 +40664,10 @@
|
|
|
40590
40664
|
generator.generate();
|
|
40591
40665
|
this._tickCache = generator.tickLookup;
|
|
40592
40666
|
this.onMidiLoad(midiFile);
|
|
40593
|
-
const player = this.
|
|
40594
|
-
|
|
40595
|
-
|
|
40596
|
-
|
|
40597
|
-
player.applyTranspositionPitches(generator.transpositionPitches);
|
|
40598
|
-
}
|
|
40667
|
+
const player = this._player;
|
|
40668
|
+
player.loadMidiFile(midiFile);
|
|
40669
|
+
player.loadBackingTrack(score, generator.syncPoints);
|
|
40670
|
+
player.applyTranspositionPitches(generator.transpositionPitches);
|
|
40599
40671
|
}
|
|
40600
40672
|
/**
|
|
40601
40673
|
* Changes the volume of the given tracks.
|
|
@@ -40633,12 +40705,9 @@
|
|
|
40633
40705
|
* ```
|
|
40634
40706
|
*/
|
|
40635
40707
|
changeTrackVolume(tracks, volume) {
|
|
40636
|
-
if (!this.player) {
|
|
40637
|
-
return;
|
|
40638
|
-
}
|
|
40639
40708
|
for (const track of tracks) {
|
|
40640
|
-
this.
|
|
40641
|
-
this.
|
|
40709
|
+
this._player.setChannelVolume(track.playbackInfo.primaryChannel, volume);
|
|
40710
|
+
this._player.setChannelVolume(track.playbackInfo.secondaryChannel, volume);
|
|
40642
40711
|
}
|
|
40643
40712
|
}
|
|
40644
40713
|
/**
|
|
@@ -40675,12 +40744,9 @@
|
|
|
40675
40744
|
* ```
|
|
40676
40745
|
*/
|
|
40677
40746
|
changeTrackSolo(tracks, solo) {
|
|
40678
|
-
if (!this.player) {
|
|
40679
|
-
return;
|
|
40680
|
-
}
|
|
40681
40747
|
for (const track of tracks) {
|
|
40682
|
-
this.
|
|
40683
|
-
this.
|
|
40748
|
+
this._player.setChannelSolo(track.playbackInfo.primaryChannel, solo);
|
|
40749
|
+
this._player.setChannelSolo(track.playbackInfo.secondaryChannel, solo);
|
|
40684
40750
|
}
|
|
40685
40751
|
}
|
|
40686
40752
|
/**
|
|
@@ -40716,12 +40782,9 @@
|
|
|
40716
40782
|
* ```
|
|
40717
40783
|
*/
|
|
40718
40784
|
changeTrackMute(tracks, mute) {
|
|
40719
|
-
if (!this.player) {
|
|
40720
|
-
return;
|
|
40721
|
-
}
|
|
40722
40785
|
for (const track of tracks) {
|
|
40723
|
-
this.
|
|
40724
|
-
this.
|
|
40786
|
+
this._player.setChannelMute(track.playbackInfo.primaryChannel, mute);
|
|
40787
|
+
this._player.setChannelMute(track.playbackInfo.secondaryChannel, mute);
|
|
40725
40788
|
}
|
|
40726
40789
|
}
|
|
40727
40790
|
/**
|
|
@@ -40759,12 +40822,9 @@
|
|
|
40759
40822
|
* ```
|
|
40760
40823
|
*/
|
|
40761
40824
|
changeTrackTranspositionPitch(tracks, semitones) {
|
|
40762
|
-
if (!this.player) {
|
|
40763
|
-
return;
|
|
40764
|
-
}
|
|
40765
40825
|
for (const track of tracks) {
|
|
40766
|
-
this.
|
|
40767
|
-
this.
|
|
40826
|
+
this._player.setChannelTranspositionPitch(track.playbackInfo.primaryChannel, semitones);
|
|
40827
|
+
this._player.setChannelTranspositionPitch(track.playbackInfo.secondaryChannel, semitones);
|
|
40768
40828
|
}
|
|
40769
40829
|
}
|
|
40770
40830
|
/**
|
|
@@ -40795,10 +40855,7 @@
|
|
|
40795
40855
|
* ```
|
|
40796
40856
|
*/
|
|
40797
40857
|
play() {
|
|
40798
|
-
|
|
40799
|
-
return false;
|
|
40800
|
-
}
|
|
40801
|
-
return this.player.play();
|
|
40858
|
+
return this._player.play();
|
|
40802
40859
|
}
|
|
40803
40860
|
/**
|
|
40804
40861
|
* Pauses the playback of the current song.
|
|
@@ -40827,10 +40884,7 @@
|
|
|
40827
40884
|
* ```
|
|
40828
40885
|
*/
|
|
40829
40886
|
pause() {
|
|
40830
|
-
|
|
40831
|
-
return;
|
|
40832
|
-
}
|
|
40833
|
-
this.player.pause();
|
|
40887
|
+
this._player.pause();
|
|
40834
40888
|
}
|
|
40835
40889
|
/**
|
|
40836
40890
|
* Toggles between play/pause depending on the current player state.
|
|
@@ -40861,10 +40915,7 @@
|
|
|
40861
40915
|
* ```
|
|
40862
40916
|
*/
|
|
40863
40917
|
playPause() {
|
|
40864
|
-
|
|
40865
|
-
return;
|
|
40866
|
-
}
|
|
40867
|
-
this.player.playPause();
|
|
40918
|
+
this._player.playPause();
|
|
40868
40919
|
}
|
|
40869
40920
|
/**
|
|
40870
40921
|
* Stops the playback of the current song, and moves the playback position back to the start.
|
|
@@ -40895,10 +40946,7 @@
|
|
|
40895
40946
|
* ```
|
|
40896
40947
|
*/
|
|
40897
40948
|
stop() {
|
|
40898
|
-
|
|
40899
|
-
return;
|
|
40900
|
-
}
|
|
40901
|
-
this.player.stop();
|
|
40949
|
+
this._player.stop();
|
|
40902
40950
|
}
|
|
40903
40951
|
/**
|
|
40904
40952
|
* Triggers the play of the given beat.
|
|
@@ -40934,15 +40982,12 @@
|
|
|
40934
40982
|
* ```
|
|
40935
40983
|
*/
|
|
40936
40984
|
playBeat(beat) {
|
|
40937
|
-
if (!this.player) {
|
|
40938
|
-
return;
|
|
40939
|
-
}
|
|
40940
40985
|
// we generate a new midi file containing only the beat
|
|
40941
40986
|
const midiFile = new MidiFile();
|
|
40942
40987
|
const handler = new AlphaSynthMidiFileHandler(midiFile);
|
|
40943
40988
|
const generator = new MidiFileGenerator(beat.voice.bar.staff.track.score, this.settings, handler);
|
|
40944
40989
|
generator.generateSingleBeat(beat);
|
|
40945
|
-
this.
|
|
40990
|
+
this._player.playOneTimeMidiFile(midiFile);
|
|
40946
40991
|
}
|
|
40947
40992
|
/**
|
|
40948
40993
|
* Triggers the play of the given note.
|
|
@@ -40977,15 +41022,12 @@
|
|
|
40977
41022
|
* ```
|
|
40978
41023
|
*/
|
|
40979
41024
|
playNote(note) {
|
|
40980
|
-
if (!this.player) {
|
|
40981
|
-
return;
|
|
40982
|
-
}
|
|
40983
41025
|
// we generate a new midi file containing only the beat
|
|
40984
41026
|
const midiFile = new MidiFile();
|
|
40985
41027
|
const handler = new AlphaSynthMidiFileHandler(midiFile);
|
|
40986
41028
|
const generator = new MidiFileGenerator(note.beat.voice.bar.staff.track.score, this.settings, handler);
|
|
40987
41029
|
generator.generateSingleNote(note);
|
|
40988
|
-
this.
|
|
41030
|
+
this._player.playOneTimeMidiFile(midiFile);
|
|
40989
41031
|
}
|
|
40990
41032
|
destroyCursors() {
|
|
40991
41033
|
if (!this._cursorWrapper) {
|
|
@@ -41008,6 +41050,7 @@
|
|
|
41008
41050
|
this._barCursor = cursors.barCursor;
|
|
41009
41051
|
this._beatCursor = cursors.beatCursor;
|
|
41010
41052
|
this._selectionWrapper = cursors.selectionWrapper;
|
|
41053
|
+
this._isInitialBeatCursorUpdate = true;
|
|
41011
41054
|
}
|
|
41012
41055
|
if (this._currentBeat !== null) {
|
|
41013
41056
|
this.cursorUpdateBeat(this._currentBeat, false, this._previousTick > 10, 1, true);
|
|
@@ -41017,36 +41060,6 @@
|
|
|
41017
41060
|
this.destroyCursors();
|
|
41018
41061
|
}
|
|
41019
41062
|
}
|
|
41020
|
-
setupPlayerEvents() {
|
|
41021
|
-
//
|
|
41022
|
-
// Hook into events
|
|
41023
|
-
this._previousTick = 0;
|
|
41024
|
-
this._playerState = PlayerState.Paused;
|
|
41025
|
-
// we need to update our position caches if we render a tablature
|
|
41026
|
-
this.renderer.postRenderFinished.on(() => {
|
|
41027
|
-
this._currentBeat = null;
|
|
41028
|
-
this.cursorUpdateTick(this._previousTick, false, 1, this._previousTick > 10);
|
|
41029
|
-
});
|
|
41030
|
-
if (this.player) {
|
|
41031
|
-
this.player.positionChanged.on(e => {
|
|
41032
|
-
this._previousTick = e.currentTick;
|
|
41033
|
-
this.uiFacade.beginInvoke(() => {
|
|
41034
|
-
const cursorSpeed = e.modifiedTempo / e.originalTempo;
|
|
41035
|
-
this.cursorUpdateTick(e.currentTick, false, cursorSpeed, false, e.isSeek);
|
|
41036
|
-
});
|
|
41037
|
-
});
|
|
41038
|
-
this.player.stateChanged.on(e => {
|
|
41039
|
-
this._playerState = e.state;
|
|
41040
|
-
if (!e.stopped && e.state === PlayerState.Paused) {
|
|
41041
|
-
const currentBeat = this._currentBeat;
|
|
41042
|
-
const tickCache = this._tickCache;
|
|
41043
|
-
if (currentBeat && tickCache) {
|
|
41044
|
-
this.player.tickPosition = tickCache.getBeatStart(currentBeat.beat);
|
|
41045
|
-
}
|
|
41046
|
-
}
|
|
41047
|
-
});
|
|
41048
|
-
}
|
|
41049
|
-
}
|
|
41050
41063
|
/**
|
|
41051
41064
|
* updates the cursors to highlight the beat at the specified tick position
|
|
41052
41065
|
* @param tick
|
|
@@ -41077,7 +41090,7 @@
|
|
|
41077
41090
|
if (!beat) {
|
|
41078
41091
|
return;
|
|
41079
41092
|
}
|
|
41080
|
-
const cache = this.
|
|
41093
|
+
const cache = this._renderer.boundsLookup;
|
|
41081
41094
|
if (!cache) {
|
|
41082
41095
|
return;
|
|
41083
41096
|
}
|
|
@@ -41087,7 +41100,7 @@
|
|
|
41087
41100
|
if (!forceUpdate &&
|
|
41088
41101
|
beat === previousBeat?.beat &&
|
|
41089
41102
|
cache === previousCache &&
|
|
41090
|
-
previousState === this.
|
|
41103
|
+
previousState === this._player.state &&
|
|
41091
41104
|
previousBeat?.start === lookupResult.start) {
|
|
41092
41105
|
return;
|
|
41093
41106
|
}
|
|
@@ -41099,7 +41112,7 @@
|
|
|
41099
41112
|
// actually show the cursor
|
|
41100
41113
|
this._currentBeat = lookupResult;
|
|
41101
41114
|
this._previousCursorCache = cache;
|
|
41102
|
-
this._previousStateForCursor = this.
|
|
41115
|
+
this._previousStateForCursor = this._player.state;
|
|
41103
41116
|
this.uiFacade.beginInvoke(() => {
|
|
41104
41117
|
this.internalCursorUpdateBeat(beat, nextBeat, duration, stop, beatsToHighlight, cache, beatBoundings, shouldScroll, lookupResult.cursorMode, cursorSpeed);
|
|
41105
41118
|
});
|
|
@@ -41110,9 +41123,9 @@
|
|
|
41110
41123
|
* @category Methods - Player
|
|
41111
41124
|
*/
|
|
41112
41125
|
scrollToCursor() {
|
|
41113
|
-
const
|
|
41114
|
-
if (
|
|
41115
|
-
this.internalScrollToCursor(barBounds);
|
|
41126
|
+
const beatBounds = this._currentBeatBounds;
|
|
41127
|
+
if (beatBounds) {
|
|
41128
|
+
this.internalScrollToCursor(beatBounds.barBounds.masterBarBounds);
|
|
41116
41129
|
}
|
|
41117
41130
|
}
|
|
41118
41131
|
internalScrollToCursor(barBoundings) {
|
|
@@ -41171,10 +41184,12 @@
|
|
|
41171
41184
|
const beatCursor = this._beatCursor;
|
|
41172
41185
|
const barBoundings = beatBoundings.barBounds.masterBarBounds;
|
|
41173
41186
|
const barBounds = barBoundings.visualBounds;
|
|
41174
|
-
|
|
41187
|
+
const previousBeatBounds = this._currentBeatBounds;
|
|
41188
|
+
this._currentBeatBounds = beatBoundings;
|
|
41175
41189
|
if (barCursor) {
|
|
41176
41190
|
barCursor.setBounds(barBounds.x, barBounds.y, barBounds.w, barBounds.h);
|
|
41177
41191
|
}
|
|
41192
|
+
const isPlayingUpdate = this._player.state === PlayerState.Playing && !stop;
|
|
41178
41193
|
let nextBeatX = barBoundings.visualBounds.x + barBoundings.visualBounds.w;
|
|
41179
41194
|
// get position of next beat on same system
|
|
41180
41195
|
if (nextBeat && cursorMode === MidiTickLookupFindBeatResultCursorMode.ToNextBext) {
|
|
@@ -41192,20 +41207,49 @@
|
|
|
41192
41207
|
if (this.settings.player.enableAnimatedBeatCursor) {
|
|
41193
41208
|
const animationWidth = nextBeatX - beatBoundings.onNotesX;
|
|
41194
41209
|
const relativePosition = this._previousTick - this._currentBeat.start;
|
|
41195
|
-
const ratioPosition = relativePosition / this._currentBeat.tickDuration;
|
|
41210
|
+
const ratioPosition = this._currentBeat.tickDuration > 0 ? relativePosition / this._currentBeat.tickDuration : 0;
|
|
41196
41211
|
startBeatX = beatBoundings.onNotesX + animationWidth * ratioPosition;
|
|
41197
41212
|
duration -= duration * ratioPosition;
|
|
41213
|
+
if (isPlayingUpdate) {
|
|
41214
|
+
// we do not "reset" the cursor if we are smoothly moving from left to right.
|
|
41215
|
+
const jumpCursor = !previousBeatBounds ||
|
|
41216
|
+
this._isInitialBeatCursorUpdate ||
|
|
41217
|
+
barBounds.y !== previousBeatBounds.barBounds.masterBarBounds.visualBounds.y ||
|
|
41218
|
+
startBeatX < previousBeatBounds.onNotesX ||
|
|
41219
|
+
barBoundings.index > previousBeatBounds.barBounds.masterBarBounds.index + 1;
|
|
41220
|
+
if (jumpCursor) {
|
|
41221
|
+
beatCursor.transitionToX(0, startBeatX);
|
|
41222
|
+
beatCursor.setBounds(startBeatX, barBounds.y, 1, barBounds.h);
|
|
41223
|
+
}
|
|
41224
|
+
// we need to put the transition to an own animation frame
|
|
41225
|
+
// otherwise the stop animation above is not applied.
|
|
41226
|
+
this.uiFacade.beginInvoke(() => {
|
|
41227
|
+
// it can happen that the cursor reaches the target position slightly too early (especially on backing tracks)
|
|
41228
|
+
// to avoid the cursor stopping, causing a wierd look, we animate the cursor to the double position in double time.
|
|
41229
|
+
// beatCursor!.transitionToX((duration / cursorSpeed), nextBeatX);
|
|
41230
|
+
const doubleEndBeatX = startBeatX + (nextBeatX - startBeatX) * 2;
|
|
41231
|
+
beatCursor.transitionToX((duration / cursorSpeed) * 2, doubleEndBeatX);
|
|
41232
|
+
});
|
|
41233
|
+
}
|
|
41234
|
+
else {
|
|
41235
|
+
beatCursor.transitionToX(0, startBeatX);
|
|
41236
|
+
beatCursor.setBounds(startBeatX, barBounds.y, 1, barBounds.h);
|
|
41237
|
+
}
|
|
41238
|
+
}
|
|
41239
|
+
else {
|
|
41240
|
+
// ticking cursor
|
|
41198
41241
|
beatCursor.transitionToX(0, startBeatX);
|
|
41242
|
+
beatCursor.setBounds(startBeatX, barBounds.y, 1, barBounds.h);
|
|
41199
41243
|
}
|
|
41200
|
-
|
|
41244
|
+
this._isInitialBeatCursorUpdate = false;
|
|
41201
41245
|
}
|
|
41202
|
-
|
|
41203
|
-
|
|
41204
|
-
this.uiFacade.removeHighlights();
|
|
41246
|
+
else {
|
|
41247
|
+
this._isInitialBeatCursorUpdate = true;
|
|
41205
41248
|
}
|
|
41249
|
+
// if playing, animate the cursor to the next beat
|
|
41250
|
+
this.uiFacade.removeHighlights();
|
|
41206
41251
|
// actively playing? -> animate cursor and highlight items
|
|
41207
41252
|
let shouldNotifyBeatChange = false;
|
|
41208
|
-
const isPlayingUpdate = this._playerState === PlayerState.Playing && !stop;
|
|
41209
41253
|
if (isPlayingUpdate) {
|
|
41210
41254
|
if (this.settings.player.enableElementHighlighting) {
|
|
41211
41255
|
for (const highlight of beatsToHighlight) {
|
|
@@ -41216,15 +41260,6 @@
|
|
|
41216
41260
|
shouldScroll = !stop;
|
|
41217
41261
|
shouldNotifyBeatChange = true;
|
|
41218
41262
|
}
|
|
41219
|
-
if (this.settings.player.enableAnimatedBeatCursor && beatCursor) {
|
|
41220
|
-
if (isPlayingUpdate) {
|
|
41221
|
-
// we need to put the transition to an own animation frame
|
|
41222
|
-
// otherwise the stop animation above is not applied.
|
|
41223
|
-
this.uiFacade.beginInvoke(() => {
|
|
41224
|
-
beatCursor.transitionToX(duration / cursorSpeed, nextBeatX);
|
|
41225
|
-
});
|
|
41226
|
-
}
|
|
41227
|
-
}
|
|
41228
41263
|
if (shouldScroll && !this._beatMouseDown && this.settings.player.scrollMode !== exports.ScrollMode.Off) {
|
|
41229
41264
|
this.internalScrollToCursor(barBoundings);
|
|
41230
41265
|
}
|
|
@@ -41314,7 +41349,7 @@
|
|
|
41314
41349
|
const realMasterBarStart = tickCache.getMasterBarStart(this._selectionStart.beat.voice.bar.masterBar);
|
|
41315
41350
|
// move to selection start
|
|
41316
41351
|
this._currentBeat = null; // reset current beat so it is updating the cursor
|
|
41317
|
-
if (this.
|
|
41352
|
+
if (this._player.state === PlayerState.Paused) {
|
|
41318
41353
|
this.cursorUpdateTick(this._tickCache.getBeatStart(this._selectionStart.beat), false, 1);
|
|
41319
41354
|
}
|
|
41320
41355
|
this.tickPosition = realMasterBarStart + this._selectionStart.beat.playbackStart;
|
|
@@ -41376,11 +41411,11 @@
|
|
|
41376
41411
|
}
|
|
41377
41412
|
const relX = e.getX(this.canvasElement);
|
|
41378
41413
|
const relY = e.getY(this.canvasElement);
|
|
41379
|
-
const beat = this.
|
|
41414
|
+
const beat = this._renderer.boundsLookup?.getBeatAtPos(relX, relY) ?? null;
|
|
41380
41415
|
if (beat) {
|
|
41381
41416
|
this.onBeatMouseDown(e, beat);
|
|
41382
41417
|
if (this.settings.core.includeNoteBounds) {
|
|
41383
|
-
const note = this.
|
|
41418
|
+
const note = this._renderer.boundsLookup?.getNoteAtPos(beat, relX, relY);
|
|
41384
41419
|
if (note) {
|
|
41385
41420
|
this.onNoteMouseDown(e, note);
|
|
41386
41421
|
}
|
|
@@ -41393,11 +41428,11 @@
|
|
|
41393
41428
|
}
|
|
41394
41429
|
const relX = e.getX(this.canvasElement);
|
|
41395
41430
|
const relY = e.getY(this.canvasElement);
|
|
41396
|
-
const beat = this.
|
|
41431
|
+
const beat = this._renderer.boundsLookup?.getBeatAtPos(relX, relY) ?? null;
|
|
41397
41432
|
if (beat) {
|
|
41398
41433
|
this.onBeatMouseMove(e, beat);
|
|
41399
41434
|
if (this._noteMouseDown) {
|
|
41400
|
-
const note = this.
|
|
41435
|
+
const note = this._renderer.boundsLookup?.getNoteAtPos(beat, relX, relY);
|
|
41401
41436
|
if (note) {
|
|
41402
41437
|
this.onNoteMouseMove(e, note);
|
|
41403
41438
|
}
|
|
@@ -41413,11 +41448,11 @@
|
|
|
41413
41448
|
}
|
|
41414
41449
|
const relX = e.getX(this.canvasElement);
|
|
41415
41450
|
const relY = e.getY(this.canvasElement);
|
|
41416
|
-
const beat = this.
|
|
41451
|
+
const beat = this._renderer.boundsLookup?.getBeatAtPos(relX, relY) ?? null;
|
|
41417
41452
|
this.onBeatMouseUp(e, beat);
|
|
41418
41453
|
if (this._noteMouseDown) {
|
|
41419
41454
|
if (beat) {
|
|
41420
|
-
const note = this.
|
|
41455
|
+
const note = this._renderer.boundsLookup?.getNoteAtPos(beat, relX, relY) ?? null;
|
|
41421
41456
|
this.onNoteMouseUp(e, note);
|
|
41422
41457
|
}
|
|
41423
41458
|
else {
|
|
@@ -41425,7 +41460,7 @@
|
|
|
41425
41460
|
}
|
|
41426
41461
|
}
|
|
41427
41462
|
});
|
|
41428
|
-
this.
|
|
41463
|
+
this._renderer.postRenderFinished.on(() => {
|
|
41429
41464
|
if (!this._selectionStart ||
|
|
41430
41465
|
this.settings.player.playerMode === exports.PlayerMode.Disabled ||
|
|
41431
41466
|
!this.settings.player.enableCursor ||
|
|
@@ -41436,7 +41471,7 @@
|
|
|
41436
41471
|
});
|
|
41437
41472
|
}
|
|
41438
41473
|
cursorSelectRange(startBeat, endBeat) {
|
|
41439
|
-
const cache = this.
|
|
41474
|
+
const cache = this._renderer.boundsLookup;
|
|
41440
41475
|
if (!cache) {
|
|
41441
41476
|
return;
|
|
41442
41477
|
}
|
|
@@ -41505,7 +41540,8 @@
|
|
|
41505
41540
|
}
|
|
41506
41541
|
this.scoreLoaded.trigger(score);
|
|
41507
41542
|
this.uiFacade.triggerEvent(this.container, 'scoreLoaded', score);
|
|
41508
|
-
if (this.
|
|
41543
|
+
if (!this.setupOrDestroyPlayer()) {
|
|
41544
|
+
// feed midi into current player (a new player will trigger a midi generation once the player is ready)
|
|
41509
41545
|
this.loadMidiForScore();
|
|
41510
41546
|
}
|
|
41511
41547
|
}
|
|
@@ -41534,6 +41570,8 @@
|
|
|
41534
41570
|
if (this._isDestroyed) {
|
|
41535
41571
|
return;
|
|
41536
41572
|
}
|
|
41573
|
+
this._currentBeat = null;
|
|
41574
|
+
this.cursorUpdateTick(this._previousTick, false, 1, true, true);
|
|
41537
41575
|
this.postRenderFinished.trigger();
|
|
41538
41576
|
this.uiFacade.triggerEvent(this.container, 'postRenderFinished', null);
|
|
41539
41577
|
}
|
|
@@ -41548,25 +41586,155 @@
|
|
|
41548
41586
|
this.error.trigger(error);
|
|
41549
41587
|
this.uiFacade.triggerEvent(this.container, 'error', error);
|
|
41550
41588
|
}
|
|
41589
|
+
/**
|
|
41590
|
+
* This event is fired when all required data for playback is loaded and ready.
|
|
41591
|
+
* @remarks
|
|
41592
|
+
* This event is fired when all required data for playback is loaded and ready. The player is ready for playback when
|
|
41593
|
+
* all background workers are started, the audio output is initialized, a soundfont is loaded, and a song was loaded into the player as midi file.
|
|
41594
|
+
*
|
|
41595
|
+
* @eventProperty
|
|
41596
|
+
* @category Events - Player
|
|
41597
|
+
* @since 0.9.4
|
|
41598
|
+
*
|
|
41599
|
+
* @example
|
|
41600
|
+
* JavaScript
|
|
41601
|
+
* ```js
|
|
41602
|
+
* const api = new alphaTab.AlphaTabApi(document.querySelector('#alphaTab'));
|
|
41603
|
+
* api.playerReady.on(() => {
|
|
41604
|
+
* enablePlayerControls();
|
|
41605
|
+
* });
|
|
41606
|
+
* ```
|
|
41607
|
+
*
|
|
41608
|
+
* @example
|
|
41609
|
+
* C#
|
|
41610
|
+
* ```cs
|
|
41611
|
+
* var api = new AlphaTabApi<MyControl>(...);
|
|
41612
|
+
* api.PlayerReady.On(() =>
|
|
41613
|
+
* {
|
|
41614
|
+
* EnablePlayerControls()
|
|
41615
|
+
* });
|
|
41616
|
+
* ```
|
|
41617
|
+
*
|
|
41618
|
+
* @example
|
|
41619
|
+
* Android
|
|
41620
|
+
* ```kotlin
|
|
41621
|
+
* val api = AlphaTabApi<MyControl>(...)
|
|
41622
|
+
* api.playerReady.on {
|
|
41623
|
+
* enablePlayerControls()
|
|
41624
|
+
* }
|
|
41625
|
+
* ```
|
|
41626
|
+
*/
|
|
41627
|
+
get playerReady() {
|
|
41628
|
+
return this._player.readyForPlayback;
|
|
41629
|
+
}
|
|
41551
41630
|
onPlayerReady() {
|
|
41552
41631
|
if (this._isDestroyed) {
|
|
41553
41632
|
return;
|
|
41554
41633
|
}
|
|
41555
|
-
this.playerReady.trigger();
|
|
41556
41634
|
this.uiFacade.triggerEvent(this.container, 'playerReady', null);
|
|
41557
41635
|
}
|
|
41636
|
+
/**
|
|
41637
|
+
* This event is fired when the playback of the whole song finished.
|
|
41638
|
+
* @remarks
|
|
41639
|
+
* This event is finished regardless on whether looping is enabled or not.
|
|
41640
|
+
*
|
|
41641
|
+
* @eventProperty
|
|
41642
|
+
* @category Events - Player
|
|
41643
|
+
* @since 0.9.4
|
|
41644
|
+
*
|
|
41645
|
+
* @example
|
|
41646
|
+
* JavaScript
|
|
41647
|
+
* ```js
|
|
41648
|
+
* const api = new alphaTab.AlphaTabApi(document.querySelector('#alphaTab'));
|
|
41649
|
+
* api.playerFinished.on((args) => {
|
|
41650
|
+
* // speed trainer
|
|
41651
|
+
* api.playbackSpeed = Math.min(1.0, api.playbackSpeed + 0.1);
|
|
41652
|
+
* });
|
|
41653
|
+
* api.isLooping = true;
|
|
41654
|
+
* api.playbackSpeed = 0.5;
|
|
41655
|
+
* api.play()
|
|
41656
|
+
* ```
|
|
41657
|
+
*
|
|
41658
|
+
* @example
|
|
41659
|
+
* C#
|
|
41660
|
+
* ```cs
|
|
41661
|
+
* var api = new AlphaTabApi<MyControl>(...);
|
|
41662
|
+
* api.PlayerFinished.On(() =>
|
|
41663
|
+
* {
|
|
41664
|
+
* // speed trainer
|
|
41665
|
+
* api.PlaybackSpeed = Math.Min(1.0, api.PlaybackSpeed + 0.1);
|
|
41666
|
+
* });
|
|
41667
|
+
* api.IsLooping = true;
|
|
41668
|
+
* api.PlaybackSpeed = 0.5;
|
|
41669
|
+
* api.Play();
|
|
41670
|
+
* ```
|
|
41671
|
+
*
|
|
41672
|
+
* @example
|
|
41673
|
+
* Android
|
|
41674
|
+
* ```kotlin
|
|
41675
|
+
* val api = AlphaTabApi<MyControl>(...)
|
|
41676
|
+
* api.playerFinished.on {
|
|
41677
|
+
* // speed trainer
|
|
41678
|
+
* api.playbackSpeed = min(1.0, api.playbackSpeed + 0.1);
|
|
41679
|
+
* }
|
|
41680
|
+
* api.isLooping = true
|
|
41681
|
+
* api.playbackSpeed = 0.5
|
|
41682
|
+
* api.play()
|
|
41683
|
+
* ```
|
|
41684
|
+
*
|
|
41685
|
+
*/
|
|
41686
|
+
get playerFinished() {
|
|
41687
|
+
return this._player.finished;
|
|
41688
|
+
}
|
|
41558
41689
|
onPlayerFinished() {
|
|
41559
41690
|
if (this._isDestroyed) {
|
|
41560
41691
|
return;
|
|
41561
41692
|
}
|
|
41562
|
-
this.playerFinished.trigger();
|
|
41563
41693
|
this.uiFacade.triggerEvent(this.container, 'playerFinished', null);
|
|
41564
41694
|
}
|
|
41695
|
+
/**
|
|
41696
|
+
* This event is fired when the SoundFont needed for playback was loaded.
|
|
41697
|
+
*
|
|
41698
|
+
* @eventProperty
|
|
41699
|
+
* @category Events - Player
|
|
41700
|
+
* @since 0.9.4
|
|
41701
|
+
*
|
|
41702
|
+
* @example
|
|
41703
|
+
* JavaScript
|
|
41704
|
+
* ```js
|
|
41705
|
+
* const api = new alphaTab.AlphaTabApi(document.querySelector('#alphaTab'));
|
|
41706
|
+
* api.soundFontLoaded.on(() => {
|
|
41707
|
+
* hideSoundFontLoadingIndicator();
|
|
41708
|
+
* });
|
|
41709
|
+
* ```
|
|
41710
|
+
*
|
|
41711
|
+
* @example
|
|
41712
|
+
* C#
|
|
41713
|
+
* ```cs
|
|
41714
|
+
* var api = new AlphaTabApi<MyControl>(...);
|
|
41715
|
+
* api.SoundFontLoaded.On(() =>
|
|
41716
|
+
* {
|
|
41717
|
+
* HideSoundFontLoadingIndicator();
|
|
41718
|
+
* });
|
|
41719
|
+
* ```
|
|
41720
|
+
*
|
|
41721
|
+
* @example
|
|
41722
|
+
* Android
|
|
41723
|
+
* ```kotlin
|
|
41724
|
+
* val api = AlphaTabApi<MyControl>(...);
|
|
41725
|
+
* api.soundFontLoaded.on {
|
|
41726
|
+
* hideSoundFontLoadingIndicator();
|
|
41727
|
+
* }
|
|
41728
|
+
* ```
|
|
41729
|
+
*
|
|
41730
|
+
*/
|
|
41731
|
+
get soundFontLoaded() {
|
|
41732
|
+
return this._player.soundFontLoaded;
|
|
41733
|
+
}
|
|
41565
41734
|
onSoundFontLoaded() {
|
|
41566
41735
|
if (this._isDestroyed) {
|
|
41567
41736
|
return;
|
|
41568
41737
|
}
|
|
41569
|
-
this.soundFontLoaded.trigger();
|
|
41570
41738
|
this.uiFacade.triggerEvent(this.container, 'soundFontLoaded', null);
|
|
41571
41739
|
}
|
|
41572
41740
|
onMidiLoad(e) {
|
|
@@ -41583,34 +41751,255 @@
|
|
|
41583
41751
|
this.midiLoaded.trigger(e);
|
|
41584
41752
|
this.uiFacade.triggerEvent(this.container, 'midiFileLoaded', e);
|
|
41585
41753
|
}
|
|
41754
|
+
/**
|
|
41755
|
+
* This event is fired when the playback state changed.
|
|
41756
|
+
*
|
|
41757
|
+
* @eventProperty
|
|
41758
|
+
* @category Events - Player
|
|
41759
|
+
* @since 0.9.4
|
|
41760
|
+
*
|
|
41761
|
+
* @example
|
|
41762
|
+
* JavaScript
|
|
41763
|
+
* ```js
|
|
41764
|
+
* const api = new alphaTab.AlphaTabApi(document.querySelector('#alphaTab'));
|
|
41765
|
+
* api.playerStateChanged.on((args) => {
|
|
41766
|
+
* updatePlayerControls(args.state, args.stopped);
|
|
41767
|
+
* });
|
|
41768
|
+
* ```
|
|
41769
|
+
*
|
|
41770
|
+
* @example
|
|
41771
|
+
* C#
|
|
41772
|
+
* ```cs
|
|
41773
|
+
* var api = new AlphaTabApi<MyControl>(...);
|
|
41774
|
+
* api.PlayerStateChanged.On(args =>
|
|
41775
|
+
* {
|
|
41776
|
+
* UpdatePlayerControls(args);
|
|
41777
|
+
* });
|
|
41778
|
+
* ```
|
|
41779
|
+
*
|
|
41780
|
+
* @example
|
|
41781
|
+
* Android
|
|
41782
|
+
* ```kotlin
|
|
41783
|
+
* val api = AlphaTabApi<MyControl>(...)
|
|
41784
|
+
* api.playerStateChanged.on { args ->
|
|
41785
|
+
* updatePlayerControls(args)
|
|
41786
|
+
* }
|
|
41787
|
+
* ```
|
|
41788
|
+
*
|
|
41789
|
+
*/
|
|
41790
|
+
get playerStateChanged() {
|
|
41791
|
+
return this._player.stateChanged;
|
|
41792
|
+
}
|
|
41586
41793
|
onPlayerStateChanged(e) {
|
|
41587
41794
|
if (this._isDestroyed) {
|
|
41588
41795
|
return;
|
|
41589
41796
|
}
|
|
41590
|
-
|
|
41797
|
+
if (!e.stopped && e.state === PlayerState.Paused) {
|
|
41798
|
+
const currentBeat = this._currentBeat;
|
|
41799
|
+
const tickCache = this._tickCache;
|
|
41800
|
+
if (currentBeat && tickCache) {
|
|
41801
|
+
this._player.tickPosition = tickCache.getBeatStart(currentBeat.beat);
|
|
41802
|
+
}
|
|
41803
|
+
}
|
|
41591
41804
|
this.uiFacade.triggerEvent(this.container, 'playerStateChanged', e);
|
|
41592
41805
|
}
|
|
41806
|
+
/**
|
|
41807
|
+
* This event is fired when the current playback position of the song changed.
|
|
41808
|
+
*
|
|
41809
|
+
* @eventProperty
|
|
41810
|
+
* @category Events - Player
|
|
41811
|
+
* @since 0.9.4
|
|
41812
|
+
*
|
|
41813
|
+
* @example
|
|
41814
|
+
* JavaScript
|
|
41815
|
+
* ```js
|
|
41816
|
+
* const api = new alphaTab.AlphaTabApi(document.querySelector('#alphaTab'));
|
|
41817
|
+
* api.playerPositionChanged.on((args) => {
|
|
41818
|
+
* updatePlayerPosition(args);
|
|
41819
|
+
* });
|
|
41820
|
+
* ```
|
|
41821
|
+
*
|
|
41822
|
+
* @example
|
|
41823
|
+
* C#
|
|
41824
|
+
* ```cs
|
|
41825
|
+
* var api = new AlphaTabApi<MyControl>(...);
|
|
41826
|
+
* api.PlayerPositionChanged.On(args =>
|
|
41827
|
+
* {
|
|
41828
|
+
* UpdatePlayerPosition(args);
|
|
41829
|
+
* });
|
|
41830
|
+
* ```
|
|
41831
|
+
*
|
|
41832
|
+
* @example
|
|
41833
|
+
* Android
|
|
41834
|
+
* ```kotlin
|
|
41835
|
+
* val api = AlphaTabApi<MyControl>(...)
|
|
41836
|
+
* api.playerPositionChanged.on { args ->
|
|
41837
|
+
* updatePlayerPosition(args)
|
|
41838
|
+
* }
|
|
41839
|
+
* ```
|
|
41840
|
+
*
|
|
41841
|
+
*/
|
|
41842
|
+
get playerPositionChanged() {
|
|
41843
|
+
return this._player.positionChanged;
|
|
41844
|
+
}
|
|
41593
41845
|
onPlayerPositionChanged(e) {
|
|
41594
41846
|
if (this._isDestroyed) {
|
|
41595
41847
|
return;
|
|
41596
41848
|
}
|
|
41597
|
-
|
|
41598
|
-
|
|
41599
|
-
|
|
41600
|
-
|
|
41849
|
+
this._previousTick = e.currentTick;
|
|
41850
|
+
this.uiFacade.beginInvoke(() => {
|
|
41851
|
+
const cursorSpeed = e.modifiedTempo / e.originalTempo;
|
|
41852
|
+
this.cursorUpdateTick(e.currentTick, false, cursorSpeed, false, e.isSeek);
|
|
41853
|
+
});
|
|
41854
|
+
this.uiFacade.triggerEvent(this.container, 'playerPositionChanged', e);
|
|
41855
|
+
}
|
|
41856
|
+
/**
|
|
41857
|
+
* This event is fired when the synthesizer played certain midi events.
|
|
41858
|
+
*
|
|
41859
|
+
* @remarks
|
|
41860
|
+
* This event is fired when the synthesizer played certain midi events. This allows reacing on various low level
|
|
41861
|
+
* audio playback elements like notes/rests played or metronome ticks.
|
|
41862
|
+
*
|
|
41863
|
+
* Refer to the [related guide](https://www.alphatab.net/docs/guides/handling-midi-events) to learn more about this feature.
|
|
41864
|
+
*
|
|
41865
|
+
* Also note that the provided data models changed significantly in {@version 1.3.0}. We try to provide backwards compatibility
|
|
41866
|
+
* until some extend but highly encourage changing to the new models in case of problems.
|
|
41867
|
+
*
|
|
41868
|
+
* @eventProperty
|
|
41869
|
+
* @category Events - Player
|
|
41870
|
+
* @since 1.2.0
|
|
41871
|
+
*
|
|
41872
|
+
* @example
|
|
41873
|
+
* JavaScript
|
|
41874
|
+
* ```js
|
|
41875
|
+
* const api = new alphaTab.AlphaTabApi(document.querySelector('#alphaTab'));
|
|
41876
|
+
* api.midiEventsPlayedFilter = [alphaTab.midi.MidiEventType.AlphaTabMetronome];
|
|
41877
|
+
* api.midiEventsPlayed.on(function(e) {
|
|
41878
|
+
* for(const midi of e.events) {
|
|
41879
|
+
* if(midi.isMetronome) {
|
|
41880
|
+
* console.log('Metronome tick ' + midi.tick);
|
|
41881
|
+
* }
|
|
41882
|
+
* }
|
|
41883
|
+
* });
|
|
41884
|
+
* ```
|
|
41885
|
+
*
|
|
41886
|
+
* @example
|
|
41887
|
+
* C#
|
|
41888
|
+
* ```cs
|
|
41889
|
+
* var api = new AlphaTabApi<MyControl>(...);
|
|
41890
|
+
* api.MidiEventsPlayedFilter = new MidiEventType[] { AlphaTab.Midi.MidiEventType.AlphaTabMetronome };
|
|
41891
|
+
* api.MidiEventsPlayed.On(e =>
|
|
41892
|
+
* {
|
|
41893
|
+
* foreach(var midi of e.events)
|
|
41894
|
+
* {
|
|
41895
|
+
* if(midi is AlphaTab.Midi.AlphaTabMetronomeEvent sysex && sysex.IsMetronome)
|
|
41896
|
+
* {
|
|
41897
|
+
* Console.WriteLine("Metronome tick " + midi.Tick);
|
|
41898
|
+
* }
|
|
41899
|
+
* }
|
|
41900
|
+
* });
|
|
41901
|
+
* ```
|
|
41902
|
+
*
|
|
41903
|
+
* @example
|
|
41904
|
+
* Android
|
|
41905
|
+
* ```kotlin
|
|
41906
|
+
* val api = AlphaTabApi<MyControl>(...);
|
|
41907
|
+
* api.midiEventsPlayedFilter = alphaTab.collections.List<alphaTab.midi.MidiEventType>( alphaTab.midi.MidiEventType.AlphaTabMetronome )
|
|
41908
|
+
* api.midiEventsPlayed.on { e ->
|
|
41909
|
+
* for (midi in e.events) {
|
|
41910
|
+
* if(midi instanceof alphaTab.midi.AlphaTabMetronomeEvent && midi.isMetronome) {
|
|
41911
|
+
* println("Metronome tick " + midi.tick);
|
|
41912
|
+
* }
|
|
41913
|
+
* }
|
|
41914
|
+
* }
|
|
41915
|
+
* ```
|
|
41916
|
+
* @see {@link MidiEvent}
|
|
41917
|
+
* @see {@link TimeSignatureEvent}
|
|
41918
|
+
* @see {@link AlphaTabMetronomeEvent}
|
|
41919
|
+
* @see {@link AlphaTabRestEvent}
|
|
41920
|
+
* @see {@link NoteOnEvent}
|
|
41921
|
+
* @see {@link NoteOffEvent}
|
|
41922
|
+
* @see {@link ControlChangeEvent}
|
|
41923
|
+
* @see {@link ProgramChangeEvent}
|
|
41924
|
+
* @see {@link TempoChangeEvent}
|
|
41925
|
+
* @see {@link PitchBendEvent}
|
|
41926
|
+
* @see {@link NoteBendEvent}
|
|
41927
|
+
* @see {@link EndOfTrackEvent}
|
|
41928
|
+
* @see {@link MetaEvent}
|
|
41929
|
+
* @see {@link MetaDataEvent}
|
|
41930
|
+
* @see {@link MetaNumberEvent}
|
|
41931
|
+
* @see {@link Midi20PerNotePitchBendEvent}
|
|
41932
|
+
* @see {@link SystemCommonEvent}
|
|
41933
|
+
* @see {@link SystemExclusiveEvent}
|
|
41934
|
+
*/
|
|
41935
|
+
get midiEventsPlayed() {
|
|
41936
|
+
return this._player.midiEventsPlayed;
|
|
41601
41937
|
}
|
|
41602
41938
|
onMidiEventsPlayed(e) {
|
|
41603
41939
|
if (this._isDestroyed) {
|
|
41604
41940
|
return;
|
|
41605
41941
|
}
|
|
41606
|
-
this.midiEventsPlayed.trigger(e);
|
|
41607
41942
|
this.uiFacade.triggerEvent(this.container, 'midiEventsPlayed', e);
|
|
41608
41943
|
}
|
|
41944
|
+
/**
|
|
41945
|
+
* This event is fired when the playback range changed.
|
|
41946
|
+
*
|
|
41947
|
+
* @eventProperty
|
|
41948
|
+
* @category Events - Player
|
|
41949
|
+
* @since 1.2.3
|
|
41950
|
+
*
|
|
41951
|
+
* @example
|
|
41952
|
+
* JavaScript
|
|
41953
|
+
* ```js
|
|
41954
|
+
* const api = new alphaTab.AlphaTabApi(document.querySelector('#alphaTab'));
|
|
41955
|
+
* api.playbackRangeChanged.on((args) => {
|
|
41956
|
+
* if (args.playbackRange) {
|
|
41957
|
+
* highlightRangeInProgressBar(args.playbackRange.startTick, args.playbackRange.endTick);
|
|
41958
|
+
* } else {
|
|
41959
|
+
* clearHighlightInProgressBar();
|
|
41960
|
+
* }
|
|
41961
|
+
* });
|
|
41962
|
+
* ```
|
|
41963
|
+
*
|
|
41964
|
+
* @example
|
|
41965
|
+
* C#
|
|
41966
|
+
* ```cs
|
|
41967
|
+
* var api = new AlphaTabApi<MyControl>(...);
|
|
41968
|
+
* api.PlaybackRangeChanged.On(args =>
|
|
41969
|
+
* {
|
|
41970
|
+
* if (args.PlaybackRange != null)
|
|
41971
|
+
* {
|
|
41972
|
+
* HighlightRangeInProgressBar(args.PlaybackRange.StartTick, args.PlaybackRange.EndTick);
|
|
41973
|
+
* }
|
|
41974
|
+
* else
|
|
41975
|
+
* {
|
|
41976
|
+
* ClearHighlightInProgressBar();
|
|
41977
|
+
* }
|
|
41978
|
+
* });
|
|
41979
|
+
* ```
|
|
41980
|
+
*
|
|
41981
|
+
* @example
|
|
41982
|
+
* Android
|
|
41983
|
+
* ```kotlin
|
|
41984
|
+
* val api = AlphaTabApi<MyControl>(...)
|
|
41985
|
+
* api.playbackRangeChanged.on { args ->
|
|
41986
|
+
* val playbackRange = args.playbackRange
|
|
41987
|
+
* if (playbackRange != null) {
|
|
41988
|
+
* highlightRangeInProgressBar(playbackRange.startTick, playbackRange.endTick)
|
|
41989
|
+
* } else {
|
|
41990
|
+
* clearHighlightInProgressBar()
|
|
41991
|
+
* }
|
|
41992
|
+
* }
|
|
41993
|
+
* ```
|
|
41994
|
+
*
|
|
41995
|
+
*/
|
|
41996
|
+
get playbackRangeChanged() {
|
|
41997
|
+
return this._player.playbackRangeChanged;
|
|
41998
|
+
}
|
|
41609
41999
|
onPlaybackRangeChanged(e) {
|
|
41610
42000
|
if (this._isDestroyed) {
|
|
41611
42001
|
return;
|
|
41612
42002
|
}
|
|
41613
|
-
this.playbackRangeChanged.trigger(e);
|
|
41614
42003
|
this.uiFacade.triggerEvent(this.container, 'playbackRangeChanged', e);
|
|
41615
42004
|
}
|
|
41616
42005
|
onSettingsUpdated() {
|
|
@@ -41672,10 +42061,7 @@
|
|
|
41672
42061
|
* ```
|
|
41673
42062
|
*/
|
|
41674
42063
|
async enumerateOutputDevices() {
|
|
41675
|
-
|
|
41676
|
-
return await this.player.output.enumerateOutputDevices();
|
|
41677
|
-
}
|
|
41678
|
-
return [];
|
|
42064
|
+
return await this._player.output.enumerateOutputDevices();
|
|
41679
42065
|
}
|
|
41680
42066
|
/**
|
|
41681
42067
|
* Changes the output device which should be used for playing the audio (player must be enabled).
|
|
@@ -41726,9 +42112,7 @@
|
|
|
41726
42112
|
* ```
|
|
41727
42113
|
*/
|
|
41728
42114
|
async setOutputDevice(device) {
|
|
41729
|
-
|
|
41730
|
-
await this.player.output.setOutputDevice(device);
|
|
41731
|
-
}
|
|
42115
|
+
await this._player.output.setOutputDevice(device);
|
|
41732
42116
|
}
|
|
41733
42117
|
/**
|
|
41734
42118
|
* The currently configured output device if changed via {@link setOutputDevice}.
|
|
@@ -41768,10 +42152,7 @@
|
|
|
41768
42152
|
*
|
|
41769
42153
|
*/
|
|
41770
42154
|
async getOutputDevice() {
|
|
41771
|
-
|
|
41772
|
-
return await this.player.output.getOutputDevice();
|
|
41773
|
-
}
|
|
41774
|
-
return null;
|
|
42155
|
+
return await this._player.output.getOutputDevice();
|
|
41775
42156
|
}
|
|
41776
42157
|
}
|
|
41777
42158
|
|
|
@@ -41948,38 +42329,52 @@
|
|
|
41948
42329
|
this.element = element;
|
|
41949
42330
|
this.mouseDown = {
|
|
41950
42331
|
on: (value) => {
|
|
41951
|
-
|
|
42332
|
+
const nativeListener = e => {
|
|
41952
42333
|
value(new BrowserMouseEventArgs(e));
|
|
41953
|
-
}
|
|
42334
|
+
};
|
|
42335
|
+
this.element.addEventListener('mousedown', nativeListener, true);
|
|
42336
|
+
return () => {
|
|
42337
|
+
this.element.removeEventListener('mousedown', nativeListener, true);
|
|
42338
|
+
};
|
|
41954
42339
|
},
|
|
41955
42340
|
off: (value) => {
|
|
41956
42341
|
}
|
|
41957
42342
|
};
|
|
41958
42343
|
this.mouseUp = {
|
|
41959
42344
|
on: (value) => {
|
|
41960
|
-
|
|
42345
|
+
const nativeListener = e => {
|
|
41961
42346
|
value(new BrowserMouseEventArgs(e));
|
|
41962
|
-
}
|
|
42347
|
+
};
|
|
42348
|
+
this.element.addEventListener('mouseup', nativeListener, true);
|
|
42349
|
+
return () => {
|
|
42350
|
+
this.element.removeEventListener('mouseup', nativeListener, true);
|
|
42351
|
+
};
|
|
41963
42352
|
},
|
|
41964
42353
|
off: (value) => {
|
|
41965
42354
|
}
|
|
41966
42355
|
};
|
|
41967
42356
|
this.mouseMove = {
|
|
41968
42357
|
on: (value) => {
|
|
41969
|
-
|
|
42358
|
+
const nativeListener = e => {
|
|
41970
42359
|
value(new BrowserMouseEventArgs(e));
|
|
41971
|
-
}
|
|
42360
|
+
};
|
|
42361
|
+
this.element.addEventListener('mousemove', nativeListener, true);
|
|
42362
|
+
return () => {
|
|
42363
|
+
this.element.removeEventListener('mousemove', nativeListener, true);
|
|
42364
|
+
};
|
|
41972
42365
|
},
|
|
41973
42366
|
off: (_) => {
|
|
41974
42367
|
}
|
|
41975
42368
|
};
|
|
42369
|
+
const container = this;
|
|
41976
42370
|
this.resize = {
|
|
41977
|
-
on: (value)
|
|
41978
|
-
if (
|
|
41979
|
-
HtmlElementContainer.resizeObserver.value.observe(
|
|
42371
|
+
on: function (value) {
|
|
42372
|
+
if (container._resizeListeners === 0) {
|
|
42373
|
+
HtmlElementContainer.resizeObserver.value.observe(container.element);
|
|
41980
42374
|
}
|
|
41981
|
-
|
|
41982
|
-
|
|
42375
|
+
container.element.addEventListener('resize', value, true);
|
|
42376
|
+
container._resizeListeners++;
|
|
42377
|
+
return () => this.off(value);
|
|
41983
42378
|
},
|
|
41984
42379
|
off: (value) => {
|
|
41985
42380
|
this.element.removeEventListener('resize', value, true);
|
|
@@ -42560,21 +42955,6 @@
|
|
|
42560
42955
|
}
|
|
42561
42956
|
}
|
|
42562
42957
|
|
|
42563
|
-
/**
|
|
42564
|
-
* Represents the progress of any data being loaded.
|
|
42565
|
-
*/
|
|
42566
|
-
class ProgressEventArgs {
|
|
42567
|
-
/**
|
|
42568
|
-
* Initializes a new instance of the {@link ProgressEventArgs} class.
|
|
42569
|
-
* @param loaded
|
|
42570
|
-
* @param total
|
|
42571
|
-
*/
|
|
42572
|
-
constructor(loaded, total) {
|
|
42573
|
-
this.loaded = loaded;
|
|
42574
|
-
this.total = total;
|
|
42575
|
-
}
|
|
42576
|
-
}
|
|
42577
|
-
|
|
42578
42958
|
/**
|
|
42579
42959
|
* a WebWorker based alphaSynth which uses the given player as output.
|
|
42580
42960
|
* @target web
|
|
@@ -42811,25 +43191,6 @@
|
|
|
42811
43191
|
append: append
|
|
42812
43192
|
});
|
|
42813
43193
|
}
|
|
42814
|
-
loadSoundFontFromUrl(url, append, progress) {
|
|
42815
|
-
Logger.debug('AlphaSynth', `Start loading Soundfont from url ${url}`);
|
|
42816
|
-
const request = new XMLHttpRequest();
|
|
42817
|
-
request.open('GET', url, true, null, null);
|
|
42818
|
-
request.responseType = 'arraybuffer';
|
|
42819
|
-
request.onload = _ => {
|
|
42820
|
-
const buffer = new Uint8Array(request.response);
|
|
42821
|
-
this.loadSoundFont(buffer, append);
|
|
42822
|
-
};
|
|
42823
|
-
request.onerror = e => {
|
|
42824
|
-
Logger.error('AlphaSynth', `Loading failed: ${e.message}`);
|
|
42825
|
-
this.soundFontLoadFailed.trigger(new FileLoadError(e.message, request));
|
|
42826
|
-
};
|
|
42827
|
-
request.onprogress = e => {
|
|
42828
|
-
Logger.debug('AlphaSynth', `Soundfont downloading: ${e.loaded}/${e.total} bytes`);
|
|
42829
|
-
progress(new ProgressEventArgs(e.loaded, e.total));
|
|
42830
|
-
};
|
|
42831
|
-
request.send();
|
|
42832
|
-
}
|
|
42833
43194
|
resetSoundFonts() {
|
|
42834
43195
|
this._synth.postMessage({
|
|
42835
43196
|
cmd: 'alphaSynth.resetSoundFonts'
|
|
@@ -43381,7 +43742,11 @@
|
|
|
43381
43742
|
}
|
|
43382
43743
|
this._padding = backingTrack.padding / 1000;
|
|
43383
43744
|
const blob = new Blob([backingTrack.rawAudioFile]);
|
|
43745
|
+
// https://html.spec.whatwg.org/multipage/media.html#loading-the-media-resource
|
|
43746
|
+
// Step 8. resets the playbackRate, we need to remember and restore it.
|
|
43747
|
+
const playbackRate = this.audioElement.playbackRate;
|
|
43384
43748
|
this.audioElement.src = URL.createObjectURL(blob);
|
|
43749
|
+
this.audioElement.playbackRate = playbackRate;
|
|
43385
43750
|
}
|
|
43386
43751
|
open(_bufferTimeInMilliseconds) {
|
|
43387
43752
|
const audioElement = document.createElement('audio');
|
|
@@ -44100,6 +44465,21 @@
|
|
|
44100
44465
|
}
|
|
44101
44466
|
}
|
|
44102
44467
|
|
|
44468
|
+
/**
|
|
44469
|
+
* Represents the progress of any data being loaded.
|
|
44470
|
+
*/
|
|
44471
|
+
class ProgressEventArgs {
|
|
44472
|
+
/**
|
|
44473
|
+
* Initializes a new instance of the {@link ProgressEventArgs} class.
|
|
44474
|
+
* @param loaded
|
|
44475
|
+
* @param total
|
|
44476
|
+
*/
|
|
44477
|
+
constructor(loaded, total) {
|
|
44478
|
+
this.loaded = loaded;
|
|
44479
|
+
this.total = total;
|
|
44480
|
+
}
|
|
44481
|
+
}
|
|
44482
|
+
|
|
44103
44483
|
/**
|
|
44104
44484
|
* @target web
|
|
44105
44485
|
*/
|
|
@@ -44343,13 +44723,29 @@
|
|
|
44343
44723
|
* @since 0.9.4
|
|
44344
44724
|
*/
|
|
44345
44725
|
loadSoundFontFromUrl(url, append) {
|
|
44346
|
-
|
|
44726
|
+
const player = this.player;
|
|
44727
|
+
if (!player) {
|
|
44347
44728
|
return;
|
|
44348
44729
|
}
|
|
44349
|
-
|
|
44350
|
-
|
|
44351
|
-
|
|
44352
|
-
|
|
44730
|
+
Logger.debug('AlphaSynth', `Start loading Soundfont from url ${url}`);
|
|
44731
|
+
const request = new XMLHttpRequest();
|
|
44732
|
+
request.open('GET', url, true, null, null);
|
|
44733
|
+
request.responseType = 'arraybuffer';
|
|
44734
|
+
request.onload = _ => {
|
|
44735
|
+
const buffer = new Uint8Array(request.response);
|
|
44736
|
+
this.loadSoundFont(buffer, append);
|
|
44737
|
+
};
|
|
44738
|
+
request.onerror = e => {
|
|
44739
|
+
Logger.error('AlphaSynth', `Loading failed: ${e.message}`);
|
|
44740
|
+
player.soundFontLoadFailed.trigger(new FileLoadError(e.message, request));
|
|
44741
|
+
};
|
|
44742
|
+
request.onprogress = e => {
|
|
44743
|
+
Logger.debug('AlphaSynth', `Soundfont downloading: ${e.loaded}/${e.total} bytes`);
|
|
44744
|
+
const args = new ProgressEventArgs(e.loaded, e.total);
|
|
44745
|
+
this.soundFontLoad.trigger(args);
|
|
44746
|
+
this.uiFacade.triggerEvent(this.container, 'soundFontLoad', args);
|
|
44747
|
+
};
|
|
44748
|
+
request.send();
|
|
44353
44749
|
}
|
|
44354
44750
|
}
|
|
44355
44751
|
|
|
@@ -46731,7 +47127,7 @@
|
|
|
46731
47127
|
return this.masterBarsRenderers[0].masterBar.index;
|
|
46732
47128
|
}
|
|
46733
47129
|
get lastBarIndex() {
|
|
46734
|
-
return this.masterBarsRenderers[this.masterBarsRenderers.length - 1].
|
|
47130
|
+
return this.masterBarsRenderers[this.masterBarsRenderers.length - 1].lastMasterBarIndex;
|
|
46735
47131
|
}
|
|
46736
47132
|
addMasterBarRenderers(tracks, renderers) {
|
|
46737
47133
|
if (tracks.length === 0) {
|
|
@@ -47545,6 +47941,9 @@
|
|
|
47545
47941
|
}
|
|
47546
47942
|
}
|
|
47547
47943
|
}
|
|
47944
|
+
else {
|
|
47945
|
+
this.tuningGlyph = null;
|
|
47946
|
+
}
|
|
47548
47947
|
}
|
|
47549
47948
|
// chord diagram glyphs
|
|
47550
47949
|
if (notation.isNotationElementVisible(exports.NotationElement.ChordDiagrams)) {
|
|
@@ -47573,6 +47972,12 @@
|
|
|
47573
47972
|
}
|
|
47574
47973
|
}
|
|
47575
47974
|
}
|
|
47975
|
+
if (this.chordDiagrams.isEmpty) {
|
|
47976
|
+
this.chordDiagrams = null;
|
|
47977
|
+
}
|
|
47978
|
+
}
|
|
47979
|
+
else {
|
|
47980
|
+
this.chordDiagrams = null;
|
|
47576
47981
|
}
|
|
47577
47982
|
}
|
|
47578
47983
|
createEmptyStaffSystem() {
|
|
@@ -60316,9 +60721,9 @@
|
|
|
60316
60721
|
print(`build date: ${VersionInfo.date}`);
|
|
60317
60722
|
}
|
|
60318
60723
|
}
|
|
60319
|
-
VersionInfo.version = '1.6.0-alpha.
|
|
60320
|
-
VersionInfo.date = '2025-05-
|
|
60321
|
-
VersionInfo.commit = '
|
|
60724
|
+
VersionInfo.version = '1.6.0-alpha.1415';
|
|
60725
|
+
VersionInfo.date = '2025-05-19T16:08:22.342Z';
|
|
60726
|
+
VersionInfo.commit = '459db69f8896a2ea8822ce5d49dcc824edd36521';
|
|
60322
60727
|
|
|
60323
60728
|
/**
|
|
60324
60729
|
* A factory for custom layout engines.
|