@coderline/alphatab 1.6.0-alpha.1405 → 1.6.0-alpha.1409
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 +952 -737
- package/dist/alphaTab.d.ts +41 -17
- package/dist/alphaTab.js +952 -737
- 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.core.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* alphaTab v1.6.0-alpha.
|
|
2
|
+
* alphaTab v1.6.0-alpha.1409 (develop, build 1409)
|
|
3
3
|
*
|
|
4
4
|
* Copyright © 2025, Daniel Kuschny and Contributors, All rights reserved.
|
|
5
5
|
*
|
|
@@ -22397,6 +22397,11 @@ class MidiFileSequencer {
|
|
|
22397
22397
|
this._mainState.eventIndex = 0;
|
|
22398
22398
|
this._mainState.syncPointIndex = 0;
|
|
22399
22399
|
this._mainState.tempoChangeIndex = 0;
|
|
22400
|
+
this._mainState.currentTempo = this._mainState.tempoChanges[0].bpm;
|
|
22401
|
+
this._mainState.modifiedTempo =
|
|
22402
|
+
this._mainState.syncPoints.length > 0
|
|
22403
|
+
? this._mainState.syncPoints[0].data.modifiedTempo
|
|
22404
|
+
: this._mainState.currentTempo;
|
|
22400
22405
|
if (this.isPlayingMain) {
|
|
22401
22406
|
const metronomeVolume = this._synthesizer.metronomeVolume;
|
|
22402
22407
|
this._synthesizer.noteOffAll(true);
|
|
@@ -22535,18 +22540,6 @@ class MidiFileSequencer {
|
|
|
22535
22540
|
this._currentState.synthData[this._currentState.eventIndex].time < this._currentState.currentTime) {
|
|
22536
22541
|
const synthEvent = this._currentState.synthData[this._currentState.eventIndex];
|
|
22537
22542
|
this._synthesizer.dispatchEvent(synthEvent);
|
|
22538
|
-
while (this._currentState.syncPointIndex < this._currentState.syncPoints.length &&
|
|
22539
|
-
this._currentState.syncPoints[this._currentState.syncPointIndex].tick < synthEvent.event.tick) {
|
|
22540
|
-
this._currentState.modifiedTempo =
|
|
22541
|
-
this._currentState.syncPoints[this._currentState.syncPointIndex].data.modifiedTempo;
|
|
22542
|
-
this._currentState.syncPointIndex++;
|
|
22543
|
-
}
|
|
22544
|
-
while (this._currentState.tempoChangeIndex < this._currentState.tempoChanges.length &&
|
|
22545
|
-
this._currentState.tempoChanges[this._currentState.tempoChangeIndex].time <= synthEvent.time) {
|
|
22546
|
-
this._currentState.currentTempo =
|
|
22547
|
-
this._currentState.tempoChanges[this._currentState.tempoChangeIndex].bpm;
|
|
22548
|
-
this._currentState.tempoChangeIndex++;
|
|
22549
|
-
}
|
|
22550
22543
|
this._currentState.eventIndex++;
|
|
22551
22544
|
anyEventsDispatched = true;
|
|
22552
22545
|
}
|
|
@@ -22576,9 +22569,6 @@ class MidiFileSequencer {
|
|
|
22576
22569
|
mainTickPositionToTimePosition(tickPosition) {
|
|
22577
22570
|
return this.tickPositionToTimePositionWithSpeed(this._mainState, tickPosition, this.playbackSpeed);
|
|
22578
22571
|
}
|
|
22579
|
-
mainTimePositionToTickPosition(timePosition) {
|
|
22580
|
-
return this.timePositionToTickPositionWithSpeed(this._mainState, timePosition, this.playbackSpeed);
|
|
22581
|
-
}
|
|
22582
22572
|
mainUpdateSyncPoints(syncPoints) {
|
|
22583
22573
|
const state = this._mainState;
|
|
22584
22574
|
syncPoints.sort((a, b) => a.tick - b.tick); // just in case
|
|
@@ -22606,7 +22596,49 @@ class MidiFileSequencer {
|
|
|
22606
22596
|
state.syncPointIndex = 0;
|
|
22607
22597
|
}
|
|
22608
22598
|
currentTimePositionToTickPosition(timePosition) {
|
|
22609
|
-
|
|
22599
|
+
const state = this._currentState;
|
|
22600
|
+
if (state.tempoChanges.length === 0) {
|
|
22601
|
+
return 0;
|
|
22602
|
+
}
|
|
22603
|
+
timePosition *= this.playbackSpeed;
|
|
22604
|
+
this.updateCurrentTempo(state, timePosition);
|
|
22605
|
+
const lastTempoChange = state.tempoChanges[state.tempoChangeIndex];
|
|
22606
|
+
const timeDiff = timePosition - lastTempoChange.time;
|
|
22607
|
+
const ticks = ((timeDiff / (60000.0 / (lastTempoChange.bpm * state.division))) | 0);
|
|
22608
|
+
// we add 1 for possible rounding errors.(floating point issuses)
|
|
22609
|
+
return lastTempoChange.ticks + ticks + 1;
|
|
22610
|
+
}
|
|
22611
|
+
updateCurrentTempo(state, timePosition) {
|
|
22612
|
+
let tempoChangeIndex = state.tempoChangeIndex;
|
|
22613
|
+
if (timePosition < state.tempoChanges[tempoChangeIndex].time) {
|
|
22614
|
+
tempoChangeIndex = 0;
|
|
22615
|
+
}
|
|
22616
|
+
while (tempoChangeIndex + 1 < state.tempoChanges.length &&
|
|
22617
|
+
state.tempoChanges[tempoChangeIndex + 1].time <= timePosition) {
|
|
22618
|
+
tempoChangeIndex++;
|
|
22619
|
+
}
|
|
22620
|
+
if (tempoChangeIndex !== state.tempoChangeIndex) {
|
|
22621
|
+
state.tempoChangeIndex = tempoChangeIndex;
|
|
22622
|
+
state.currentTempo = state.tempoChanges[state.tempoChangeIndex].bpm;
|
|
22623
|
+
}
|
|
22624
|
+
const syncPoints = state.syncPoints;
|
|
22625
|
+
if (syncPoints.length > 0) {
|
|
22626
|
+
let syncPointIndex = Math.min(state.syncPointIndex, syncPoints.length - 1);
|
|
22627
|
+
if (timePosition < syncPoints[syncPointIndex].data.millisecondOffset) {
|
|
22628
|
+
syncPointIndex = 0;
|
|
22629
|
+
}
|
|
22630
|
+
while (syncPointIndex + 1 < syncPoints.length &&
|
|
22631
|
+
syncPoints[syncPointIndex + 1].data.millisecondOffset <= timePosition) {
|
|
22632
|
+
syncPointIndex++;
|
|
22633
|
+
}
|
|
22634
|
+
if (syncPointIndex !== state.syncPointIndex) {
|
|
22635
|
+
state.syncPointIndex = syncPointIndex;
|
|
22636
|
+
state.modifiedTempo = syncPoints[syncPointIndex].data.modifiedTempo;
|
|
22637
|
+
}
|
|
22638
|
+
}
|
|
22639
|
+
else {
|
|
22640
|
+
state.modifiedTempo = state.currentTempo;
|
|
22641
|
+
}
|
|
22610
22642
|
}
|
|
22611
22643
|
mainTimePositionFromBackingTrack(timePosition, backingTrackLength) {
|
|
22612
22644
|
const mainState = this._mainState;
|
|
@@ -22614,11 +22646,8 @@ class MidiFileSequencer {
|
|
|
22614
22646
|
if (timePosition < 0 || syncPoints.length === 0) {
|
|
22615
22647
|
return timePosition;
|
|
22616
22648
|
}
|
|
22617
|
-
|
|
22618
|
-
|
|
22619
|
-
syncPoints[syncPointIndex + 1].data.millisecondOffset <= timePosition) {
|
|
22620
|
-
syncPointIndex++;
|
|
22621
|
-
}
|
|
22649
|
+
this.updateCurrentTempo(this._mainState, timePosition);
|
|
22650
|
+
const syncPointIndex = Math.min(mainState.syncPointIndex, syncPoints.length - 1);
|
|
22622
22651
|
const currentSyncPoint = syncPoints[syncPointIndex];
|
|
22623
22652
|
const timeDiff = timePosition - currentSyncPoint.data.millisecondOffset;
|
|
22624
22653
|
let alphaTabTimeDiff;
|
|
@@ -22640,7 +22669,10 @@ class MidiFileSequencer {
|
|
|
22640
22669
|
return timePosition;
|
|
22641
22670
|
}
|
|
22642
22671
|
timePosition *= this.playbackSpeed;
|
|
22643
|
-
let syncPointIndex =
|
|
22672
|
+
let syncPointIndex = Math.min(mainState.syncPointIndex, syncPoints.length - 1);
|
|
22673
|
+
if (timePosition < syncPoints[syncPointIndex].time) {
|
|
22674
|
+
syncPointIndex = 0;
|
|
22675
|
+
}
|
|
22644
22676
|
while (syncPointIndex + 1 < syncPoints.length && syncPoints[syncPointIndex + 1].time <= timePosition) {
|
|
22645
22677
|
syncPointIndex++;
|
|
22646
22678
|
}
|
|
@@ -22678,26 +22710,6 @@ class MidiFileSequencer {
|
|
|
22678
22710
|
timePosition += tickPosition * (60000.0 / (bpm * state.division));
|
|
22679
22711
|
return timePosition / playbackSpeed;
|
|
22680
22712
|
}
|
|
22681
|
-
timePositionToTickPositionWithSpeed(state, timePosition, playbackSpeed) {
|
|
22682
|
-
timePosition *= playbackSpeed;
|
|
22683
|
-
let ticks = 0;
|
|
22684
|
-
let bpm = 120.0;
|
|
22685
|
-
let lastChange = 0;
|
|
22686
|
-
// find start and bpm of last tempo change before time
|
|
22687
|
-
for (const c of state.tempoChanges) {
|
|
22688
|
-
if (timePosition < c.time) {
|
|
22689
|
-
break;
|
|
22690
|
-
}
|
|
22691
|
-
ticks = c.ticks;
|
|
22692
|
-
bpm = c.bpm;
|
|
22693
|
-
lastChange = c.time;
|
|
22694
|
-
}
|
|
22695
|
-
// add the missing ticks
|
|
22696
|
-
timePosition -= lastChange;
|
|
22697
|
-
ticks += (timePosition / (60000.0 / (bpm * state.division))) | 0;
|
|
22698
|
-
// we add 1 for possible rounding errors.(floating point issuses)
|
|
22699
|
-
return ticks + 1;
|
|
22700
|
-
}
|
|
22701
22713
|
get internalEndTime() {
|
|
22702
22714
|
if (this.isPlayingMain) {
|
|
22703
22715
|
return !this.mainPlaybackRange ? this._currentState.endTime : this._currentState.playbackRangeEndTime;
|
|
@@ -26916,7 +26928,7 @@ class TinySoundFont {
|
|
|
26916
26928
|
return processedEvents;
|
|
26917
26929
|
}
|
|
26918
26930
|
processMidiMessage(e) {
|
|
26919
|
-
Logger.debug('Midi', `Processing Midi message ${MidiEventType[e.type]}/${e.tick}`);
|
|
26931
|
+
//Logger.debug('Midi', `Processing Midi message ${MidiEventType[e.type]}/${e.tick}`);
|
|
26920
26932
|
const command = e.type;
|
|
26921
26933
|
switch (command) {
|
|
26922
26934
|
case MidiEventType.TimeSignature:
|
|
@@ -28037,6 +28049,9 @@ class EventEmitter {
|
|
|
28037
28049
|
}
|
|
28038
28050
|
on(value) {
|
|
28039
28051
|
this._listeners.push(value);
|
|
28052
|
+
return () => {
|
|
28053
|
+
this.off(value);
|
|
28054
|
+
};
|
|
28040
28055
|
}
|
|
28041
28056
|
off(value) {
|
|
28042
28057
|
this._listeners = this._listeners.filter(l => l !== value);
|
|
@@ -28056,6 +28071,9 @@ class EventEmitterOfT {
|
|
|
28056
28071
|
}
|
|
28057
28072
|
on(value) {
|
|
28058
28073
|
this._listeners.push(value);
|
|
28074
|
+
return () => {
|
|
28075
|
+
this.off(value);
|
|
28076
|
+
};
|
|
28059
28077
|
}
|
|
28060
28078
|
off(value) {
|
|
28061
28079
|
this._listeners = this._listeners.filter(l => l !== value);
|
|
@@ -28452,7 +28470,7 @@ class AlphaSynthBase {
|
|
|
28452
28470
|
endTick = this.sequencer.currentEndTick;
|
|
28453
28471
|
}
|
|
28454
28472
|
if (this._tickPosition >= endTick) {
|
|
28455
|
-
// fully done with playback of remaining samples?
|
|
28473
|
+
// fully done with playback of remaining samples?
|
|
28456
28474
|
if (this._notPlayedSamples <= 0) {
|
|
28457
28475
|
this._notPlayedSamples = 0;
|
|
28458
28476
|
if (this.sequencer.isPlayingCountIn) {
|
|
@@ -35802,6 +35820,27 @@ class MidiFileGenerator {
|
|
|
35802
35820
|
controller.moveNext();
|
|
35803
35821
|
previousMasterBar = bar;
|
|
35804
35822
|
}
|
|
35823
|
+
// here we interpolate the sync point which marks the end of the sync.
|
|
35824
|
+
// Sync points define new tempos at certain positions.
|
|
35825
|
+
// looking from the last sync point to the end we do not assume the end where the audio ends,
|
|
35826
|
+
// but where it ends according to the BPM and the remaining ticks.
|
|
35827
|
+
if (this.syncPoints.length > 0) {
|
|
35828
|
+
const lastSyncPoint = this.syncPoints[this.syncPoints.length - 1];
|
|
35829
|
+
const endTick = controller.currentTick;
|
|
35830
|
+
const remainingTicks = endTick - lastSyncPoint.tick;
|
|
35831
|
+
if (remainingTicks > 0) {
|
|
35832
|
+
const syncPointData = new SyncPointData();
|
|
35833
|
+
// last occurence of the last bar
|
|
35834
|
+
syncPointData.barOccurence = barOccurence.get(this._score.masterBars.length - 1);
|
|
35835
|
+
// same tempo as last point
|
|
35836
|
+
syncPointData.modifiedTempo = lastSyncPoint.data.modifiedTempo;
|
|
35837
|
+
// interpolated end from last syncPoint
|
|
35838
|
+
syncPointData.millisecondOffset =
|
|
35839
|
+
lastSyncPoint.data.millisecondOffset +
|
|
35840
|
+
MidiUtils.ticksToMillis(remainingTicks, syncPointData.modifiedTempo);
|
|
35841
|
+
this.syncPoints.push(new BackingTrackSyncPoint(endTick, syncPointData));
|
|
35842
|
+
}
|
|
35843
|
+
}
|
|
35805
35844
|
for (const track of this._score.tracks) {
|
|
35806
35845
|
this._handler.finishTrack(track.index, controller.currentTick);
|
|
35807
35846
|
}
|
|
@@ -38293,6 +38332,270 @@ class ExternalMediaPlayer extends BackingTrackPlayer {
|
|
|
38293
38332
|
}
|
|
38294
38333
|
}
|
|
38295
38334
|
|
|
38335
|
+
/**
|
|
38336
|
+
* A {@link IAlphaSynth} implementation wrapping and underling other {@link IAlphaSynth}
|
|
38337
|
+
* allowing dynamic changing of the underlying instance without loosing aspects like the
|
|
38338
|
+
* main playback information and event listeners.
|
|
38339
|
+
*
|
|
38340
|
+
* @remarks
|
|
38341
|
+
* This wrapper is used when re-exposing the underlying player via {@link AlphaTabApiBase} to integrators.
|
|
38342
|
+
* Even with dynamic switching between synthesizer, backing tracks etc. aspects like volume, playbackspeed,
|
|
38343
|
+
* event listeners etc. should not be lost.
|
|
38344
|
+
*/
|
|
38345
|
+
class AlphaSynthWrapper {
|
|
38346
|
+
constructor() {
|
|
38347
|
+
// relevant state information we want to remember when switching between player instances
|
|
38348
|
+
this._masterVolume = 1;
|
|
38349
|
+
this._metronomeVolume = 0;
|
|
38350
|
+
this._countInVolume = 0;
|
|
38351
|
+
this._playbackSpeed = 1;
|
|
38352
|
+
this._isLooping = false;
|
|
38353
|
+
this._midiEventsPlayedFilter = [];
|
|
38354
|
+
this.ready = new EventEmitter();
|
|
38355
|
+
this.readyForPlayback = new EventEmitter();
|
|
38356
|
+
this.finished = new EventEmitter();
|
|
38357
|
+
this.soundFontLoaded = new EventEmitter();
|
|
38358
|
+
this.soundFontLoadFailed = new EventEmitterOfT();
|
|
38359
|
+
this.midiLoaded = new EventEmitterOfT();
|
|
38360
|
+
this.midiLoadFailed = new EventEmitterOfT();
|
|
38361
|
+
this.stateChanged = new EventEmitterOfT();
|
|
38362
|
+
this.positionChanged = new EventEmitterOfT();
|
|
38363
|
+
this.midiEventsPlayed = new EventEmitterOfT();
|
|
38364
|
+
this.playbackRangeChanged = new EventEmitterOfT();
|
|
38365
|
+
}
|
|
38366
|
+
get instance() {
|
|
38367
|
+
return this._instance;
|
|
38368
|
+
}
|
|
38369
|
+
set instance(value) {
|
|
38370
|
+
this._instance = value;
|
|
38371
|
+
// unregister all events from previous instance
|
|
38372
|
+
const unregister = this._instanceEventUnregister;
|
|
38373
|
+
if (unregister) {
|
|
38374
|
+
for (const e of unregister) {
|
|
38375
|
+
e();
|
|
38376
|
+
}
|
|
38377
|
+
}
|
|
38378
|
+
if (value) {
|
|
38379
|
+
// regsiter to events of new player and forward them to existing listeners
|
|
38380
|
+
const newUnregister = [];
|
|
38381
|
+
newUnregister.push(value.ready.on(() => this.ready.trigger()));
|
|
38382
|
+
newUnregister.push(value.readyForPlayback.on(() => this.readyForPlayback.trigger()));
|
|
38383
|
+
newUnregister.push(value.finished.on(() => this.finished.trigger()));
|
|
38384
|
+
newUnregister.push(value.soundFontLoaded.on(() => this.soundFontLoaded.trigger()));
|
|
38385
|
+
newUnregister.push(value.soundFontLoadFailed.on(e => this.soundFontLoadFailed.trigger(e)));
|
|
38386
|
+
newUnregister.push(value.midiLoaded.on(e => this.midiLoaded.trigger(e)));
|
|
38387
|
+
newUnregister.push(value.midiLoadFailed.on(e => this.midiLoadFailed.trigger(e)));
|
|
38388
|
+
newUnregister.push(value.stateChanged.on(e => this.stateChanged.trigger(e)));
|
|
38389
|
+
newUnregister.push(value.positionChanged.on(e => this.positionChanged.trigger(e)));
|
|
38390
|
+
newUnregister.push(value.midiEventsPlayed.on(e => this.midiEventsPlayed.trigger(e)));
|
|
38391
|
+
newUnregister.push(value.playbackRangeChanged.on(e => this.playbackRangeChanged.trigger(e)));
|
|
38392
|
+
this._instanceEventUnregister = newUnregister;
|
|
38393
|
+
// restore state on new player
|
|
38394
|
+
if (this.isReady) {
|
|
38395
|
+
value.masterVolume = this._masterVolume;
|
|
38396
|
+
value.metronomeVolume = this._metronomeVolume;
|
|
38397
|
+
value.countInVolume = this._countInVolume;
|
|
38398
|
+
value.playbackSpeed = this._playbackSpeed;
|
|
38399
|
+
value.isLooping = this._isLooping;
|
|
38400
|
+
value.midiEventsPlayedFilter = this._midiEventsPlayedFilter;
|
|
38401
|
+
}
|
|
38402
|
+
else {
|
|
38403
|
+
newUnregister.push(value.ready.on(() => {
|
|
38404
|
+
value.masterVolume = this._masterVolume;
|
|
38405
|
+
value.metronomeVolume = this._metronomeVolume;
|
|
38406
|
+
value.countInVolume = this._countInVolume;
|
|
38407
|
+
value.playbackSpeed = this._playbackSpeed;
|
|
38408
|
+
value.isLooping = this._isLooping;
|
|
38409
|
+
value.midiEventsPlayedFilter = this._midiEventsPlayedFilter;
|
|
38410
|
+
}));
|
|
38411
|
+
}
|
|
38412
|
+
}
|
|
38413
|
+
else {
|
|
38414
|
+
this._instanceEventUnregister = undefined;
|
|
38415
|
+
}
|
|
38416
|
+
}
|
|
38417
|
+
get output() {
|
|
38418
|
+
return this._instance.output;
|
|
38419
|
+
}
|
|
38420
|
+
get isReady() {
|
|
38421
|
+
return this._instance ? this._instance.isReady : false;
|
|
38422
|
+
}
|
|
38423
|
+
get isReadyForPlayback() {
|
|
38424
|
+
return this._instance ? this._instance.isReadyForPlayback : false;
|
|
38425
|
+
}
|
|
38426
|
+
get state() {
|
|
38427
|
+
return this._instance ? this._instance.state : PlayerState.Paused;
|
|
38428
|
+
}
|
|
38429
|
+
get logLevel() {
|
|
38430
|
+
return Logger.logLevel;
|
|
38431
|
+
}
|
|
38432
|
+
set logLevel(value) {
|
|
38433
|
+
Logger.logLevel = value;
|
|
38434
|
+
if (this._instance) {
|
|
38435
|
+
this._instance.logLevel = value;
|
|
38436
|
+
}
|
|
38437
|
+
}
|
|
38438
|
+
get masterVolume() {
|
|
38439
|
+
return this._masterVolume;
|
|
38440
|
+
}
|
|
38441
|
+
set masterVolume(value) {
|
|
38442
|
+
value = Math.max(value, SynthConstants.MinVolume);
|
|
38443
|
+
this._masterVolume = value;
|
|
38444
|
+
if (this._instance) {
|
|
38445
|
+
this._instance.masterVolume = value;
|
|
38446
|
+
}
|
|
38447
|
+
}
|
|
38448
|
+
get metronomeVolume() {
|
|
38449
|
+
return this._metronomeVolume;
|
|
38450
|
+
}
|
|
38451
|
+
set metronomeVolume(value) {
|
|
38452
|
+
value = Math.max(value, SynthConstants.MinVolume);
|
|
38453
|
+
this._metronomeVolume = value;
|
|
38454
|
+
if (this._instance) {
|
|
38455
|
+
this._instance.metronomeVolume = value;
|
|
38456
|
+
}
|
|
38457
|
+
}
|
|
38458
|
+
get playbackSpeed() {
|
|
38459
|
+
return this._playbackSpeed;
|
|
38460
|
+
}
|
|
38461
|
+
set playbackSpeed(value) {
|
|
38462
|
+
this._playbackSpeed = value;
|
|
38463
|
+
if (this._instance) {
|
|
38464
|
+
this._instance.playbackSpeed = value;
|
|
38465
|
+
}
|
|
38466
|
+
}
|
|
38467
|
+
get tickPosition() {
|
|
38468
|
+
return this._instance ? this._instance.tickPosition : 0;
|
|
38469
|
+
}
|
|
38470
|
+
set tickPosition(value) {
|
|
38471
|
+
if (this._instance) {
|
|
38472
|
+
this._instance.tickPosition = value;
|
|
38473
|
+
}
|
|
38474
|
+
}
|
|
38475
|
+
get timePosition() {
|
|
38476
|
+
return this._instance ? this._instance.timePosition : 0;
|
|
38477
|
+
}
|
|
38478
|
+
set timePosition(value) {
|
|
38479
|
+
if (this._instance) {
|
|
38480
|
+
this._instance.timePosition = value;
|
|
38481
|
+
}
|
|
38482
|
+
}
|
|
38483
|
+
get playbackRange() {
|
|
38484
|
+
return this._instance ? this._instance.playbackRange : null;
|
|
38485
|
+
}
|
|
38486
|
+
set playbackRange(value) {
|
|
38487
|
+
if (this._instance) {
|
|
38488
|
+
this._instance.playbackRange = value;
|
|
38489
|
+
}
|
|
38490
|
+
}
|
|
38491
|
+
get isLooping() {
|
|
38492
|
+
return this._isLooping;
|
|
38493
|
+
}
|
|
38494
|
+
set isLooping(value) {
|
|
38495
|
+
this._isLooping = value;
|
|
38496
|
+
if (this._instance) {
|
|
38497
|
+
this._instance.isLooping = value;
|
|
38498
|
+
}
|
|
38499
|
+
}
|
|
38500
|
+
get countInVolume() {
|
|
38501
|
+
return this._countInVolume;
|
|
38502
|
+
}
|
|
38503
|
+
set countInVolume(value) {
|
|
38504
|
+
this._countInVolume = value;
|
|
38505
|
+
if (this._instance) {
|
|
38506
|
+
this._instance.countInVolume = value;
|
|
38507
|
+
}
|
|
38508
|
+
}
|
|
38509
|
+
get midiEventsPlayedFilter() {
|
|
38510
|
+
return this._midiEventsPlayedFilter;
|
|
38511
|
+
}
|
|
38512
|
+
set midiEventsPlayedFilter(value) {
|
|
38513
|
+
this._midiEventsPlayedFilter = value;
|
|
38514
|
+
if (this._instance) {
|
|
38515
|
+
this._instance.midiEventsPlayedFilter = value;
|
|
38516
|
+
}
|
|
38517
|
+
}
|
|
38518
|
+
destroy() {
|
|
38519
|
+
if (this._instance) {
|
|
38520
|
+
this._instance.destroy();
|
|
38521
|
+
this._instance = undefined;
|
|
38522
|
+
}
|
|
38523
|
+
}
|
|
38524
|
+
play() {
|
|
38525
|
+
return this._instance ? this._instance.play() : false;
|
|
38526
|
+
}
|
|
38527
|
+
pause() {
|
|
38528
|
+
if (this._instance) {
|
|
38529
|
+
this._instance.pause();
|
|
38530
|
+
}
|
|
38531
|
+
}
|
|
38532
|
+
playPause() {
|
|
38533
|
+
if (this._instance) {
|
|
38534
|
+
this._instance.playPause();
|
|
38535
|
+
}
|
|
38536
|
+
}
|
|
38537
|
+
stop() {
|
|
38538
|
+
if (this._instance) {
|
|
38539
|
+
this._instance.stop();
|
|
38540
|
+
}
|
|
38541
|
+
}
|
|
38542
|
+
playOneTimeMidiFile(midi) {
|
|
38543
|
+
if (this._instance) {
|
|
38544
|
+
this._instance.playOneTimeMidiFile(midi);
|
|
38545
|
+
}
|
|
38546
|
+
}
|
|
38547
|
+
loadSoundFont(data, append) {
|
|
38548
|
+
if (this._instance) {
|
|
38549
|
+
this._instance.loadSoundFont(data, append);
|
|
38550
|
+
}
|
|
38551
|
+
}
|
|
38552
|
+
resetSoundFonts() {
|
|
38553
|
+
if (this._instance) {
|
|
38554
|
+
this._instance.resetSoundFonts();
|
|
38555
|
+
}
|
|
38556
|
+
}
|
|
38557
|
+
loadMidiFile(midi) {
|
|
38558
|
+
if (this._instance) {
|
|
38559
|
+
this._instance.loadMidiFile(midi);
|
|
38560
|
+
}
|
|
38561
|
+
}
|
|
38562
|
+
loadBackingTrack(score, syncPoints) {
|
|
38563
|
+
if (this._instance) {
|
|
38564
|
+
this._instance.loadBackingTrack(score, syncPoints);
|
|
38565
|
+
}
|
|
38566
|
+
}
|
|
38567
|
+
applyTranspositionPitches(transpositionPitches) {
|
|
38568
|
+
if (this._instance) {
|
|
38569
|
+
this._instance.applyTranspositionPitches(transpositionPitches);
|
|
38570
|
+
}
|
|
38571
|
+
}
|
|
38572
|
+
setChannelTranspositionPitch(channel, semitones) {
|
|
38573
|
+
if (this._instance) {
|
|
38574
|
+
this._instance.setChannelTranspositionPitch(channel, semitones);
|
|
38575
|
+
}
|
|
38576
|
+
}
|
|
38577
|
+
setChannelMute(channel, mute) {
|
|
38578
|
+
if (this._instance) {
|
|
38579
|
+
this._instance.setChannelMute(channel, mute);
|
|
38580
|
+
}
|
|
38581
|
+
}
|
|
38582
|
+
resetChannelStates() {
|
|
38583
|
+
if (this._instance) {
|
|
38584
|
+
this._instance.resetChannelStates();
|
|
38585
|
+
}
|
|
38586
|
+
}
|
|
38587
|
+
setChannelSolo(channel, solo) {
|
|
38588
|
+
if (this._instance) {
|
|
38589
|
+
this._instance.setChannelSolo(channel, solo);
|
|
38590
|
+
}
|
|
38591
|
+
}
|
|
38592
|
+
setChannelVolume(channel, volume) {
|
|
38593
|
+
if (this._instance) {
|
|
38594
|
+
this._instance.setChannelVolume(channel, volume);
|
|
38595
|
+
}
|
|
38596
|
+
}
|
|
38597
|
+
}
|
|
38598
|
+
|
|
38296
38599
|
class SelectionInfo {
|
|
38297
38600
|
constructor(beat) {
|
|
38298
38601
|
this.bounds = null;
|
|
@@ -38383,43 +38686,13 @@ class AlphaTabApiBase {
|
|
|
38383
38686
|
this._tracks = [];
|
|
38384
38687
|
this._actualPlayerMode = PlayerMode.Disabled;
|
|
38385
38688
|
this._tickCache = null;
|
|
38386
|
-
/**
|
|
38387
|
-
* The alphaSynth player used for playback.
|
|
38388
|
-
* @remarks
|
|
38389
|
-
* This is the low-level API to the Midi synthesizer used for playback.
|
|
38390
|
-
* Gets access to the underling {@link IAlphaSynth} that is used for the audio playback.
|
|
38391
|
-
* @category Properties - Player
|
|
38392
|
-
* @since 0.9.4
|
|
38393
|
-
* @example
|
|
38394
|
-
* JavaScript
|
|
38395
|
-
* ```js
|
|
38396
|
-
* const api = new alphaTab.AlphaTabApi(document.querySelector('#alphaTab'));
|
|
38397
|
-
* setupPlayerEvents(api.settings);
|
|
38398
|
-
* ```
|
|
38399
|
-
*
|
|
38400
|
-
* @example
|
|
38401
|
-
* C#
|
|
38402
|
-
* ```cs
|
|
38403
|
-
* var api = new AlphaTabApi<MyControl>(...);
|
|
38404
|
-
* SetupPlayerEvents(api.Player);
|
|
38405
|
-
* ```
|
|
38406
|
-
*
|
|
38407
|
-
* @example
|
|
38408
|
-
* Android
|
|
38409
|
-
* ```kotlin
|
|
38410
|
-
* val api = AlphaTabApi<MyControl>(...)
|
|
38411
|
-
* setupPlayerEvents(api.player)
|
|
38412
|
-
* ```
|
|
38413
|
-
*/
|
|
38414
|
-
this.player = null;
|
|
38415
38689
|
this._cursorWrapper = null;
|
|
38416
38690
|
this._barCursor = null;
|
|
38417
38691
|
this._beatCursor = null;
|
|
38418
38692
|
this._selectionWrapper = null;
|
|
38419
38693
|
this._previousTick = 0;
|
|
38420
|
-
this._playerState = PlayerState.Paused;
|
|
38421
38694
|
this._currentBeat = null;
|
|
38422
|
-
this.
|
|
38695
|
+
this._currentBeatBounds = null;
|
|
38423
38696
|
this._previousStateForCursor = PlayerState.Paused;
|
|
38424
38697
|
this._previousCursorCache = null;
|
|
38425
38698
|
this._lastScroll = 0;
|
|
@@ -38990,133 +39263,6 @@ class AlphaTabApiBase {
|
|
|
38990
39263
|
*
|
|
38991
39264
|
*/
|
|
38992
39265
|
this.error = new EventEmitterOfT();
|
|
38993
|
-
/**
|
|
38994
|
-
* This event is fired when all required data for playback is loaded and ready.
|
|
38995
|
-
* @remarks
|
|
38996
|
-
* This event is fired when all required data for playback is loaded and ready. The player is ready for playback when
|
|
38997
|
-
* 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.
|
|
38998
|
-
*
|
|
38999
|
-
* @eventProperty
|
|
39000
|
-
* @category Events - Player
|
|
39001
|
-
* @since 0.9.4
|
|
39002
|
-
*
|
|
39003
|
-
* @example
|
|
39004
|
-
* JavaScript
|
|
39005
|
-
* ```js
|
|
39006
|
-
* const api = new alphaTab.AlphaTabApi(document.querySelector('#alphaTab'));
|
|
39007
|
-
* api.playerReady.on(() => {
|
|
39008
|
-
* enablePlayerControls();
|
|
39009
|
-
* });
|
|
39010
|
-
* ```
|
|
39011
|
-
*
|
|
39012
|
-
* @example
|
|
39013
|
-
* C#
|
|
39014
|
-
* ```cs
|
|
39015
|
-
* var api = new AlphaTabApi<MyControl>(...);
|
|
39016
|
-
* api.PlayerReady.On(() =>
|
|
39017
|
-
* {
|
|
39018
|
-
* EnablePlayerControls()
|
|
39019
|
-
* });
|
|
39020
|
-
* ```
|
|
39021
|
-
*
|
|
39022
|
-
* @example
|
|
39023
|
-
* Android
|
|
39024
|
-
* ```kotlin
|
|
39025
|
-
* val api = AlphaTabApi<MyControl>(...)
|
|
39026
|
-
* api.playerReady.on {
|
|
39027
|
-
* enablePlayerControls()
|
|
39028
|
-
* }
|
|
39029
|
-
* ```
|
|
39030
|
-
*/
|
|
39031
|
-
this.playerReady = new EventEmitter();
|
|
39032
|
-
/**
|
|
39033
|
-
* This event is fired when the playback of the whole song finished.
|
|
39034
|
-
* @remarks
|
|
39035
|
-
* This event is finished regardless on whether looping is enabled or not.
|
|
39036
|
-
*
|
|
39037
|
-
* @eventProperty
|
|
39038
|
-
* @category Events - Player
|
|
39039
|
-
* @since 0.9.4
|
|
39040
|
-
*
|
|
39041
|
-
* @example
|
|
39042
|
-
* JavaScript
|
|
39043
|
-
* ```js
|
|
39044
|
-
* const api = new alphaTab.AlphaTabApi(document.querySelector('#alphaTab'));
|
|
39045
|
-
* api.playerFinished.on((args) => {
|
|
39046
|
-
* // speed trainer
|
|
39047
|
-
* api.playbackSpeed = Math.min(1.0, api.playbackSpeed + 0.1);
|
|
39048
|
-
* });
|
|
39049
|
-
* api.isLooping = true;
|
|
39050
|
-
* api.playbackSpeed = 0.5;
|
|
39051
|
-
* api.play()
|
|
39052
|
-
* ```
|
|
39053
|
-
*
|
|
39054
|
-
* @example
|
|
39055
|
-
* C#
|
|
39056
|
-
* ```cs
|
|
39057
|
-
* var api = new AlphaTabApi<MyControl>(...);
|
|
39058
|
-
* api.PlayerFinished.On(() =>
|
|
39059
|
-
* {
|
|
39060
|
-
* // speed trainer
|
|
39061
|
-
* api.PlaybackSpeed = Math.Min(1.0, api.PlaybackSpeed + 0.1);
|
|
39062
|
-
* });
|
|
39063
|
-
* api.IsLooping = true;
|
|
39064
|
-
* api.PlaybackSpeed = 0.5;
|
|
39065
|
-
* api.Play();
|
|
39066
|
-
* ```
|
|
39067
|
-
*
|
|
39068
|
-
* @example
|
|
39069
|
-
* Android
|
|
39070
|
-
* ```kotlin
|
|
39071
|
-
* val api = AlphaTabApi<MyControl>(...)
|
|
39072
|
-
* api.playerFinished.on {
|
|
39073
|
-
* // speed trainer
|
|
39074
|
-
* api.playbackSpeed = min(1.0, api.playbackSpeed + 0.1);
|
|
39075
|
-
* }
|
|
39076
|
-
* api.isLooping = true
|
|
39077
|
-
* api.playbackSpeed = 0.5
|
|
39078
|
-
* api.play()
|
|
39079
|
-
* ```
|
|
39080
|
-
*
|
|
39081
|
-
*/
|
|
39082
|
-
this.playerFinished = new EventEmitter();
|
|
39083
|
-
/**
|
|
39084
|
-
* This event is fired when the SoundFont needed for playback was loaded.
|
|
39085
|
-
*
|
|
39086
|
-
* @eventProperty
|
|
39087
|
-
* @category Events - Player
|
|
39088
|
-
* @since 0.9.4
|
|
39089
|
-
*
|
|
39090
|
-
* @example
|
|
39091
|
-
* JavaScript
|
|
39092
|
-
* ```js
|
|
39093
|
-
* const api = new alphaTab.AlphaTabApi(document.querySelector('#alphaTab'));
|
|
39094
|
-
* api.soundFontLoaded.on(() => {
|
|
39095
|
-
* hideSoundFontLoadingIndicator();
|
|
39096
|
-
* });
|
|
39097
|
-
* ```
|
|
39098
|
-
*
|
|
39099
|
-
* @example
|
|
39100
|
-
* C#
|
|
39101
|
-
* ```cs
|
|
39102
|
-
* var api = new AlphaTabApi<MyControl>(...);
|
|
39103
|
-
* api.SoundFontLoaded.On(() =>
|
|
39104
|
-
* {
|
|
39105
|
-
* HideSoundFontLoadingIndicator();
|
|
39106
|
-
* });
|
|
39107
|
-
* ```
|
|
39108
|
-
*
|
|
39109
|
-
* @example
|
|
39110
|
-
* Android
|
|
39111
|
-
* ```kotlin
|
|
39112
|
-
* val api = AlphaTabApi<MyControl>(...);
|
|
39113
|
-
* api.soundFontLoaded.on {
|
|
39114
|
-
* hideSoundFontLoadingIndicator();
|
|
39115
|
-
* }
|
|
39116
|
-
* ```
|
|
39117
|
-
*
|
|
39118
|
-
*/
|
|
39119
|
-
this.soundFontLoaded = new EventEmitter();
|
|
39120
39266
|
/**
|
|
39121
39267
|
* This event is fired when a Midi file is being loaded.
|
|
39122
39268
|
*
|
|
@@ -39204,213 +39350,6 @@ class AlphaTabApiBase {
|
|
|
39204
39350
|
*
|
|
39205
39351
|
*/
|
|
39206
39352
|
this.midiLoaded = new EventEmitterOfT();
|
|
39207
|
-
/**
|
|
39208
|
-
* This event is fired when the playback state changed.
|
|
39209
|
-
*
|
|
39210
|
-
* @eventProperty
|
|
39211
|
-
* @category Events - Player
|
|
39212
|
-
* @since 0.9.4
|
|
39213
|
-
*
|
|
39214
|
-
* @example
|
|
39215
|
-
* JavaScript
|
|
39216
|
-
* ```js
|
|
39217
|
-
* const api = new alphaTab.AlphaTabApi(document.querySelector('#alphaTab'));
|
|
39218
|
-
* api.playerStateChanged.on((args) => {
|
|
39219
|
-
* updatePlayerControls(args.state, args.stopped);
|
|
39220
|
-
* });
|
|
39221
|
-
* ```
|
|
39222
|
-
*
|
|
39223
|
-
* @example
|
|
39224
|
-
* C#
|
|
39225
|
-
* ```cs
|
|
39226
|
-
* var api = new AlphaTabApi<MyControl>(...);
|
|
39227
|
-
* api.PlayerStateChanged.On(args =>
|
|
39228
|
-
* {
|
|
39229
|
-
* UpdatePlayerControls(args);
|
|
39230
|
-
* });
|
|
39231
|
-
* ```
|
|
39232
|
-
*
|
|
39233
|
-
* @example
|
|
39234
|
-
* Android
|
|
39235
|
-
* ```kotlin
|
|
39236
|
-
* val api = AlphaTabApi<MyControl>(...)
|
|
39237
|
-
* api.playerStateChanged.on { args ->
|
|
39238
|
-
* updatePlayerControls(args)
|
|
39239
|
-
* }
|
|
39240
|
-
* ```
|
|
39241
|
-
*
|
|
39242
|
-
*/
|
|
39243
|
-
this.playerStateChanged = new EventEmitterOfT();
|
|
39244
|
-
/**
|
|
39245
|
-
* This event is fired when the current playback position of the song changed.
|
|
39246
|
-
*
|
|
39247
|
-
* @eventProperty
|
|
39248
|
-
* @category Events - Player
|
|
39249
|
-
* @since 0.9.4
|
|
39250
|
-
*
|
|
39251
|
-
* @example
|
|
39252
|
-
* JavaScript
|
|
39253
|
-
* ```js
|
|
39254
|
-
* const api = new alphaTab.AlphaTabApi(document.querySelector('#alphaTab'));
|
|
39255
|
-
* api.playerPositionChanged.on((args) => {
|
|
39256
|
-
* updatePlayerPosition(args);
|
|
39257
|
-
* });
|
|
39258
|
-
* ```
|
|
39259
|
-
*
|
|
39260
|
-
* @example
|
|
39261
|
-
* C#
|
|
39262
|
-
* ```cs
|
|
39263
|
-
* var api = new AlphaTabApi<MyControl>(...);
|
|
39264
|
-
* api.PlayerPositionChanged.On(args =>
|
|
39265
|
-
* {
|
|
39266
|
-
* UpdatePlayerPosition(args);
|
|
39267
|
-
* });
|
|
39268
|
-
* ```
|
|
39269
|
-
*
|
|
39270
|
-
* @example
|
|
39271
|
-
* Android
|
|
39272
|
-
* ```kotlin
|
|
39273
|
-
* val api = AlphaTabApi<MyControl>(...)
|
|
39274
|
-
* api.playerPositionChanged.on { args ->
|
|
39275
|
-
* updatePlayerPosition(args)
|
|
39276
|
-
* }
|
|
39277
|
-
* ```
|
|
39278
|
-
*
|
|
39279
|
-
*/
|
|
39280
|
-
this.playerPositionChanged = new EventEmitterOfT();
|
|
39281
|
-
/**
|
|
39282
|
-
* This event is fired when the synthesizer played certain midi events.
|
|
39283
|
-
*
|
|
39284
|
-
* @remarks
|
|
39285
|
-
* This event is fired when the synthesizer played certain midi events. This allows reacing on various low level
|
|
39286
|
-
* audio playback elements like notes/rests played or metronome ticks.
|
|
39287
|
-
*
|
|
39288
|
-
* Refer to the [related guide](https://www.alphatab.net/docs/guides/handling-midi-events) to learn more about this feature.
|
|
39289
|
-
*
|
|
39290
|
-
* Also note that the provided data models changed significantly in {@version 1.3.0}. We try to provide backwards compatibility
|
|
39291
|
-
* until some extend but highly encourage changing to the new models in case of problems.
|
|
39292
|
-
*
|
|
39293
|
-
* @eventProperty
|
|
39294
|
-
* @category Events - Player
|
|
39295
|
-
* @since 1.2.0
|
|
39296
|
-
*
|
|
39297
|
-
* @example
|
|
39298
|
-
* JavaScript
|
|
39299
|
-
* ```js
|
|
39300
|
-
* const api = new alphaTab.AlphaTabApi(document.querySelector('#alphaTab'));
|
|
39301
|
-
* api.midiEventsPlayedFilter = [alphaTab.midi.MidiEventType.AlphaTabMetronome];
|
|
39302
|
-
* api.midiEventsPlayed.on(function(e) {
|
|
39303
|
-
* for(const midi of e.events) {
|
|
39304
|
-
* if(midi.isMetronome) {
|
|
39305
|
-
* console.log('Metronome tick ' + midi.tick);
|
|
39306
|
-
* }
|
|
39307
|
-
* }
|
|
39308
|
-
* });
|
|
39309
|
-
* ```
|
|
39310
|
-
*
|
|
39311
|
-
* @example
|
|
39312
|
-
* C#
|
|
39313
|
-
* ```cs
|
|
39314
|
-
* var api = new AlphaTabApi<MyControl>(...);
|
|
39315
|
-
* api.MidiEventsPlayedFilter = new MidiEventType[] { AlphaTab.Midi.MidiEventType.AlphaTabMetronome };
|
|
39316
|
-
* api.MidiEventsPlayed.On(e =>
|
|
39317
|
-
* {
|
|
39318
|
-
* foreach(var midi of e.events)
|
|
39319
|
-
* {
|
|
39320
|
-
* if(midi is AlphaTab.Midi.AlphaTabMetronomeEvent sysex && sysex.IsMetronome)
|
|
39321
|
-
* {
|
|
39322
|
-
* Console.WriteLine("Metronome tick " + midi.Tick);
|
|
39323
|
-
* }
|
|
39324
|
-
* }
|
|
39325
|
-
* });
|
|
39326
|
-
* ```
|
|
39327
|
-
*
|
|
39328
|
-
* @example
|
|
39329
|
-
* Android
|
|
39330
|
-
* ```kotlin
|
|
39331
|
-
* val api = AlphaTabApi<MyControl>(...);
|
|
39332
|
-
* api.midiEventsPlayedFilter = alphaTab.collections.List<alphaTab.midi.MidiEventType>( alphaTab.midi.MidiEventType.AlphaTabMetronome )
|
|
39333
|
-
* api.midiEventsPlayed.on { e ->
|
|
39334
|
-
* for (midi in e.events) {
|
|
39335
|
-
* if(midi instanceof alphaTab.midi.AlphaTabMetronomeEvent && midi.isMetronome) {
|
|
39336
|
-
* println("Metronome tick " + midi.tick);
|
|
39337
|
-
* }
|
|
39338
|
-
* }
|
|
39339
|
-
* }
|
|
39340
|
-
* ```
|
|
39341
|
-
* @see {@link MidiEvent}
|
|
39342
|
-
* @see {@link TimeSignatureEvent}
|
|
39343
|
-
* @see {@link AlphaTabMetronomeEvent}
|
|
39344
|
-
* @see {@link AlphaTabRestEvent}
|
|
39345
|
-
* @see {@link NoteOnEvent}
|
|
39346
|
-
* @see {@link NoteOffEvent}
|
|
39347
|
-
* @see {@link ControlChangeEvent}
|
|
39348
|
-
* @see {@link ProgramChangeEvent}
|
|
39349
|
-
* @see {@link TempoChangeEvent}
|
|
39350
|
-
* @see {@link PitchBendEvent}
|
|
39351
|
-
* @see {@link NoteBendEvent}
|
|
39352
|
-
* @see {@link EndOfTrackEvent}
|
|
39353
|
-
* @see {@link MetaEvent}
|
|
39354
|
-
* @see {@link MetaDataEvent}
|
|
39355
|
-
* @see {@link MetaNumberEvent}
|
|
39356
|
-
* @see {@link Midi20PerNotePitchBendEvent}
|
|
39357
|
-
* @see {@link SystemCommonEvent}
|
|
39358
|
-
* @see {@link SystemExclusiveEvent}
|
|
39359
|
-
*/
|
|
39360
|
-
this.midiEventsPlayed = new EventEmitterOfT();
|
|
39361
|
-
/**
|
|
39362
|
-
* This event is fired when the playback range changed.
|
|
39363
|
-
*
|
|
39364
|
-
* @eventProperty
|
|
39365
|
-
* @category Events - Player
|
|
39366
|
-
* @since 1.2.3
|
|
39367
|
-
*
|
|
39368
|
-
* @example
|
|
39369
|
-
* JavaScript
|
|
39370
|
-
* ```js
|
|
39371
|
-
* const api = new alphaTab.AlphaTabApi(document.querySelector('#alphaTab'));
|
|
39372
|
-
* api.playbackRangeChanged.on((args) => {
|
|
39373
|
-
* if (args.playbackRange) {
|
|
39374
|
-
* highlightRangeInProgressBar(args.playbackRange.startTick, args.playbackRange.endTick);
|
|
39375
|
-
* } else {
|
|
39376
|
-
* clearHighlightInProgressBar();
|
|
39377
|
-
* }
|
|
39378
|
-
* });
|
|
39379
|
-
* ```
|
|
39380
|
-
*
|
|
39381
|
-
* @example
|
|
39382
|
-
* C#
|
|
39383
|
-
* ```cs
|
|
39384
|
-
* var api = new AlphaTabApi<MyControl>(...);
|
|
39385
|
-
* api.PlaybackRangeChanged.On(args =>
|
|
39386
|
-
* {
|
|
39387
|
-
* if (args.PlaybackRange != null)
|
|
39388
|
-
* {
|
|
39389
|
-
* HighlightRangeInProgressBar(args.PlaybackRange.StartTick, args.PlaybackRange.EndTick);
|
|
39390
|
-
* }
|
|
39391
|
-
* else
|
|
39392
|
-
* {
|
|
39393
|
-
* ClearHighlightInProgressBar();
|
|
39394
|
-
* }
|
|
39395
|
-
* });
|
|
39396
|
-
* ```
|
|
39397
|
-
*
|
|
39398
|
-
* @example
|
|
39399
|
-
* Android
|
|
39400
|
-
* ```kotlin
|
|
39401
|
-
* val api = AlphaTabApi<MyControl>(...)
|
|
39402
|
-
* api.playbackRangeChanged.on { args ->
|
|
39403
|
-
* val playbackRange = args.playbackRange
|
|
39404
|
-
* if (playbackRange != null) {
|
|
39405
|
-
* highlightRangeInProgressBar(playbackRange.startTick, playbackRange.endTick)
|
|
39406
|
-
* } else {
|
|
39407
|
-
* clearHighlightInProgressBar()
|
|
39408
|
-
* }
|
|
39409
|
-
* }
|
|
39410
|
-
* ```
|
|
39411
|
-
*
|
|
39412
|
-
*/
|
|
39413
|
-
this.playbackRangeChanged = new EventEmitterOfT();
|
|
39414
39353
|
/**
|
|
39415
39354
|
* @internal
|
|
39416
39355
|
*/
|
|
@@ -39466,8 +39405,9 @@ class AlphaTabApiBase {
|
|
|
39466
39405
|
this.appendRenderResult(null); // marks last element
|
|
39467
39406
|
});
|
|
39468
39407
|
this.renderer.error.on(this.onError.bind(this));
|
|
39408
|
+
this.setupPlayerWrapper();
|
|
39469
39409
|
if (this.settings.player.playerMode !== PlayerMode.Disabled) {
|
|
39470
|
-
this.
|
|
39410
|
+
this.setupOrDestroyPlayer();
|
|
39471
39411
|
}
|
|
39472
39412
|
this.setupClickHandling();
|
|
39473
39413
|
// delay rendering to allow ui to hook up with events first.
|
|
@@ -39475,6 +39415,36 @@ class AlphaTabApiBase {
|
|
|
39475
39415
|
this.uiFacade.initialRender();
|
|
39476
39416
|
});
|
|
39477
39417
|
}
|
|
39418
|
+
setupPlayerWrapper() {
|
|
39419
|
+
const player = new AlphaSynthWrapper();
|
|
39420
|
+
this._player = player;
|
|
39421
|
+
player.ready.on(() => {
|
|
39422
|
+
this.loadMidiForScore();
|
|
39423
|
+
});
|
|
39424
|
+
player.readyForPlayback.on(() => {
|
|
39425
|
+
this.onPlayerReady();
|
|
39426
|
+
if (this.tracks) {
|
|
39427
|
+
for (const track of this.tracks) {
|
|
39428
|
+
const volume = track.playbackInfo.volume / 16;
|
|
39429
|
+
player.setChannelVolume(track.playbackInfo.primaryChannel, volume);
|
|
39430
|
+
player.setChannelVolume(track.playbackInfo.secondaryChannel, volume);
|
|
39431
|
+
}
|
|
39432
|
+
}
|
|
39433
|
+
});
|
|
39434
|
+
player.soundFontLoaded.on(this.onSoundFontLoaded.bind(this));
|
|
39435
|
+
player.soundFontLoadFailed.on(e => {
|
|
39436
|
+
this.onError(e);
|
|
39437
|
+
});
|
|
39438
|
+
player.midiLoaded.on(this.onMidiLoaded.bind(this));
|
|
39439
|
+
player.midiLoadFailed.on(e => {
|
|
39440
|
+
this.onError(e);
|
|
39441
|
+
});
|
|
39442
|
+
player.stateChanged.on(this.onPlayerStateChanged.bind(this));
|
|
39443
|
+
player.positionChanged.on(this.onPlayerPositionChanged.bind(this));
|
|
39444
|
+
player.midiEventsPlayed.on(this.onMidiEventsPlayed.bind(this));
|
|
39445
|
+
player.playbackRangeChanged.on(this.onPlaybackRangeChanged.bind(this));
|
|
39446
|
+
player.finished.on(this.onPlayerFinished.bind(this));
|
|
39447
|
+
}
|
|
39478
39448
|
/**
|
|
39479
39449
|
* Destroys the alphaTab control and restores the initial state of the UI.
|
|
39480
39450
|
* @remarks
|
|
@@ -39507,9 +39477,7 @@ class AlphaTabApiBase {
|
|
|
39507
39477
|
*/
|
|
39508
39478
|
destroy() {
|
|
39509
39479
|
this._isDestroyed = true;
|
|
39510
|
-
|
|
39511
|
-
this.player.destroy();
|
|
39512
|
-
}
|
|
39480
|
+
this._player.destroy();
|
|
39513
39481
|
this.uiFacade.destroy();
|
|
39514
39482
|
this.renderer.destroy();
|
|
39515
39483
|
}
|
|
@@ -39557,14 +39525,8 @@ class AlphaTabApiBase {
|
|
|
39557
39525
|
ModelUtils.applyPitchOffsets(this.settings, score);
|
|
39558
39526
|
}
|
|
39559
39527
|
this.renderer.updateSettings(this.settings);
|
|
39560
|
-
|
|
39561
|
-
|
|
39562
|
-
if (this.setupPlayer() && score) {
|
|
39563
|
-
this.loadMidiForScore();
|
|
39564
|
-
}
|
|
39565
|
-
}
|
|
39566
|
-
else {
|
|
39567
|
-
this.destroyPlayer();
|
|
39528
|
+
if (this.setupOrDestroyPlayer()) {
|
|
39529
|
+
this.loadMidiForScore();
|
|
39568
39530
|
}
|
|
39569
39531
|
this.onSettingsUpdated();
|
|
39570
39532
|
}
|
|
@@ -39871,9 +39833,6 @@ class AlphaTabApiBase {
|
|
|
39871
39833
|
* ```
|
|
39872
39834
|
*/
|
|
39873
39835
|
loadSoundFont(data, append = false) {
|
|
39874
|
-
if (!this.player) {
|
|
39875
|
-
return false;
|
|
39876
|
-
}
|
|
39877
39836
|
return this.uiFacade.loadSoundFont(data, append);
|
|
39878
39837
|
}
|
|
39879
39838
|
/**
|
|
@@ -39919,10 +39878,7 @@ class AlphaTabApiBase {
|
|
|
39919
39878
|
* ```
|
|
39920
39879
|
*/
|
|
39921
39880
|
resetSoundFonts() {
|
|
39922
|
-
|
|
39923
|
-
return;
|
|
39924
|
-
}
|
|
39925
|
-
this.player.resetSoundFonts();
|
|
39881
|
+
this._player.resetSoundFonts();
|
|
39926
39882
|
}
|
|
39927
39883
|
/**
|
|
39928
39884
|
* Initiates a re-rendering of the current setup.
|
|
@@ -40036,6 +39992,37 @@ class AlphaTabApiBase {
|
|
|
40036
39992
|
get boundsLookup() {
|
|
40037
39993
|
return this.renderer.boundsLookup;
|
|
40038
39994
|
}
|
|
39995
|
+
/**
|
|
39996
|
+
* The alphaSynth player used for playback.
|
|
39997
|
+
* @remarks
|
|
39998
|
+
* This is the low-level API to the Midi synthesizer used for playback.
|
|
39999
|
+
* Gets access to the underling {@link IAlphaSynth} that is used for the audio playback.
|
|
40000
|
+
* @category Properties - Player
|
|
40001
|
+
* @since 0.9.4
|
|
40002
|
+
* @example
|
|
40003
|
+
* JavaScript
|
|
40004
|
+
* ```js
|
|
40005
|
+
* const api = new alphaTab.AlphaTabApi(document.querySelector('#alphaTab'));
|
|
40006
|
+
* setupPlayerEvents(api.settings);
|
|
40007
|
+
* ```
|
|
40008
|
+
*
|
|
40009
|
+
* @example
|
|
40010
|
+
* C#
|
|
40011
|
+
* ```cs
|
|
40012
|
+
* var api = new AlphaTabApi<MyControl>(...);
|
|
40013
|
+
* SetupPlayerEvents(api.Player);
|
|
40014
|
+
* ```
|
|
40015
|
+
*
|
|
40016
|
+
* @example
|
|
40017
|
+
* Android
|
|
40018
|
+
* ```kotlin
|
|
40019
|
+
* val api = AlphaTabApi<MyControl>(...)
|
|
40020
|
+
* setupPlayerEvents(api.player)
|
|
40021
|
+
* ```
|
|
40022
|
+
*/
|
|
40023
|
+
get player() {
|
|
40024
|
+
return this._player.instance ? this._player : null;
|
|
40025
|
+
}
|
|
40039
40026
|
/**
|
|
40040
40027
|
* Whether the player is ready for starting the playback.
|
|
40041
40028
|
* @remarks
|
|
@@ -40065,10 +40052,7 @@ class AlphaTabApiBase {
|
|
|
40065
40052
|
* ```
|
|
40066
40053
|
*/
|
|
40067
40054
|
get isReadyForPlayback() {
|
|
40068
|
-
|
|
40069
|
-
return false;
|
|
40070
|
-
}
|
|
40071
|
-
return this.player.isReadyForPlayback;
|
|
40055
|
+
return this._player.isReadyForPlayback;
|
|
40072
40056
|
}
|
|
40073
40057
|
/**
|
|
40074
40058
|
* The current player state.
|
|
@@ -40098,10 +40082,7 @@ class AlphaTabApiBase {
|
|
|
40098
40082
|
* ```
|
|
40099
40083
|
*/
|
|
40100
40084
|
get playerState() {
|
|
40101
|
-
|
|
40102
|
-
return PlayerState.Paused;
|
|
40103
|
-
}
|
|
40104
|
-
return this.player.state;
|
|
40085
|
+
return this._player.state;
|
|
40105
40086
|
}
|
|
40106
40087
|
/**
|
|
40107
40088
|
* The current master volume as percentage (0-1).
|
|
@@ -40131,15 +40112,10 @@ class AlphaTabApiBase {
|
|
|
40131
40112
|
* ```
|
|
40132
40113
|
*/
|
|
40133
40114
|
get masterVolume() {
|
|
40134
|
-
|
|
40135
|
-
return 0;
|
|
40136
|
-
}
|
|
40137
|
-
return this.player.masterVolume;
|
|
40115
|
+
return this._player.masterVolume;
|
|
40138
40116
|
}
|
|
40139
40117
|
set masterVolume(value) {
|
|
40140
|
-
|
|
40141
|
-
this.player.masterVolume = value;
|
|
40142
|
-
}
|
|
40118
|
+
this._player.masterVolume = value;
|
|
40143
40119
|
}
|
|
40144
40120
|
/**
|
|
40145
40121
|
* The metronome volume as percentage (0-1).
|
|
@@ -40170,15 +40146,10 @@ class AlphaTabApiBase {
|
|
|
40170
40146
|
* ```
|
|
40171
40147
|
*/
|
|
40172
40148
|
get metronomeVolume() {
|
|
40173
|
-
|
|
40174
|
-
return 0;
|
|
40175
|
-
}
|
|
40176
|
-
return this.player.metronomeVolume;
|
|
40149
|
+
return this._player.metronomeVolume;
|
|
40177
40150
|
}
|
|
40178
40151
|
set metronomeVolume(value) {
|
|
40179
|
-
|
|
40180
|
-
this.player.metronomeVolume = value;
|
|
40181
|
-
}
|
|
40152
|
+
this._player.metronomeVolume = value;
|
|
40182
40153
|
}
|
|
40183
40154
|
/**
|
|
40184
40155
|
* The volume of the count-in metronome ticks.
|
|
@@ -40209,15 +40180,10 @@ class AlphaTabApiBase {
|
|
|
40209
40180
|
* ```
|
|
40210
40181
|
*/
|
|
40211
40182
|
get countInVolume() {
|
|
40212
|
-
|
|
40213
|
-
return 0;
|
|
40214
|
-
}
|
|
40215
|
-
return this.player.countInVolume;
|
|
40183
|
+
return this._player.countInVolume;
|
|
40216
40184
|
}
|
|
40217
40185
|
set countInVolume(value) {
|
|
40218
|
-
|
|
40219
|
-
this.player.countInVolume = value;
|
|
40220
|
-
}
|
|
40186
|
+
this._player.countInVolume = value;
|
|
40221
40187
|
}
|
|
40222
40188
|
/**
|
|
40223
40189
|
* The midi events which will trigger the `midiEventsPlayed` event
|
|
@@ -40276,15 +40242,10 @@ class AlphaTabApiBase {
|
|
|
40276
40242
|
* ```
|
|
40277
40243
|
*/
|
|
40278
40244
|
get midiEventsPlayedFilter() {
|
|
40279
|
-
|
|
40280
|
-
return [];
|
|
40281
|
-
}
|
|
40282
|
-
return this.player.midiEventsPlayedFilter;
|
|
40245
|
+
return this._player.midiEventsPlayedFilter;
|
|
40283
40246
|
}
|
|
40284
40247
|
set midiEventsPlayedFilter(value) {
|
|
40285
|
-
|
|
40286
|
-
this.player.midiEventsPlayedFilter = value;
|
|
40287
|
-
}
|
|
40248
|
+
this._player.midiEventsPlayedFilter = value;
|
|
40288
40249
|
}
|
|
40289
40250
|
/**
|
|
40290
40251
|
* The position within the song in midi ticks.
|
|
@@ -40312,15 +40273,10 @@ class AlphaTabApiBase {
|
|
|
40312
40273
|
* ```
|
|
40313
40274
|
*/
|
|
40314
40275
|
get tickPosition() {
|
|
40315
|
-
|
|
40316
|
-
return 0;
|
|
40317
|
-
}
|
|
40318
|
-
return this.player.tickPosition;
|
|
40276
|
+
return this._player.tickPosition;
|
|
40319
40277
|
}
|
|
40320
40278
|
set tickPosition(value) {
|
|
40321
|
-
|
|
40322
|
-
this.player.tickPosition = value;
|
|
40323
|
-
}
|
|
40279
|
+
this._player.tickPosition = value;
|
|
40324
40280
|
}
|
|
40325
40281
|
/**
|
|
40326
40282
|
* The position within the song in milliseconds
|
|
@@ -40348,15 +40304,10 @@ class AlphaTabApiBase {
|
|
|
40348
40304
|
* ```
|
|
40349
40305
|
*/
|
|
40350
40306
|
get timePosition() {
|
|
40351
|
-
|
|
40352
|
-
return 0;
|
|
40353
|
-
}
|
|
40354
|
-
return this.player.timePosition;
|
|
40307
|
+
return this._player.timePosition;
|
|
40355
40308
|
}
|
|
40356
40309
|
set timePosition(value) {
|
|
40357
|
-
|
|
40358
|
-
this.player.timePosition = value;
|
|
40359
|
-
}
|
|
40310
|
+
this._player.timePosition = value;
|
|
40360
40311
|
}
|
|
40361
40312
|
/**
|
|
40362
40313
|
* The range of the song that should be played.
|
|
@@ -40390,17 +40341,12 @@ class AlphaTabApiBase {
|
|
|
40390
40341
|
* ```
|
|
40391
40342
|
*/
|
|
40392
40343
|
get playbackRange() {
|
|
40393
|
-
|
|
40394
|
-
return null;
|
|
40395
|
-
}
|
|
40396
|
-
return this.player.playbackRange;
|
|
40344
|
+
return this._player.playbackRange;
|
|
40397
40345
|
}
|
|
40398
40346
|
set playbackRange(value) {
|
|
40399
|
-
|
|
40400
|
-
|
|
40401
|
-
|
|
40402
|
-
this.updateSelectionCursor(value);
|
|
40403
|
-
}
|
|
40347
|
+
this._player.playbackRange = value;
|
|
40348
|
+
if (this.settings.player.enableCursor) {
|
|
40349
|
+
this.updateSelectionCursor(value);
|
|
40404
40350
|
}
|
|
40405
40351
|
}
|
|
40406
40352
|
/**
|
|
@@ -40432,15 +40378,10 @@ class AlphaTabApiBase {
|
|
|
40432
40378
|
* ```
|
|
40433
40379
|
*/
|
|
40434
40380
|
get playbackSpeed() {
|
|
40435
|
-
|
|
40436
|
-
return 0;
|
|
40437
|
-
}
|
|
40438
|
-
return this.player.playbackSpeed;
|
|
40381
|
+
return this._player.playbackSpeed;
|
|
40439
40382
|
}
|
|
40440
40383
|
set playbackSpeed(value) {
|
|
40441
|
-
|
|
40442
|
-
this.player.playbackSpeed = value;
|
|
40443
|
-
}
|
|
40384
|
+
this._player.playbackSpeed = value;
|
|
40444
40385
|
}
|
|
40445
40386
|
/**
|
|
40446
40387
|
* Whether the playback should automatically restart after it finished.
|
|
@@ -40471,27 +40412,17 @@ class AlphaTabApiBase {
|
|
|
40471
40412
|
* ```
|
|
40472
40413
|
*/
|
|
40473
40414
|
get isLooping() {
|
|
40474
|
-
|
|
40475
|
-
return false;
|
|
40476
|
-
}
|
|
40477
|
-
return this.player.isLooping;
|
|
40415
|
+
return this._player.isLooping;
|
|
40478
40416
|
}
|
|
40479
40417
|
set isLooping(value) {
|
|
40480
|
-
|
|
40481
|
-
this.player.isLooping = value;
|
|
40482
|
-
}
|
|
40418
|
+
this._player.isLooping = value;
|
|
40483
40419
|
}
|
|
40484
40420
|
destroyPlayer() {
|
|
40485
|
-
|
|
40486
|
-
return;
|
|
40487
|
-
}
|
|
40488
|
-
this.player.destroy();
|
|
40489
|
-
this.player = null;
|
|
40421
|
+
this._player.destroy();
|
|
40490
40422
|
this._previousTick = 0;
|
|
40491
|
-
this._playerState = PlayerState.Paused;
|
|
40492
40423
|
this.destroyCursors();
|
|
40493
40424
|
}
|
|
40494
|
-
|
|
40425
|
+
setupOrDestroyPlayer() {
|
|
40495
40426
|
let mode = this.settings.player.playerMode;
|
|
40496
40427
|
if (mode === PlayerMode.EnabledAutomatic) {
|
|
40497
40428
|
const score = this.score;
|
|
@@ -40505,66 +40436,34 @@ class AlphaTabApiBase {
|
|
|
40505
40436
|
mode = PlayerMode.EnabledSynthesizer;
|
|
40506
40437
|
}
|
|
40507
40438
|
}
|
|
40439
|
+
let newPlayer = null;
|
|
40508
40440
|
if (mode !== this._actualPlayerMode) {
|
|
40509
40441
|
this.destroyPlayer();
|
|
40442
|
+
switch (mode) {
|
|
40443
|
+
case PlayerMode.Disabled:
|
|
40444
|
+
newPlayer = null;
|
|
40445
|
+
break;
|
|
40446
|
+
case PlayerMode.EnabledSynthesizer:
|
|
40447
|
+
newPlayer = this.uiFacade.createWorkerPlayer();
|
|
40448
|
+
break;
|
|
40449
|
+
case PlayerMode.EnabledBackingTrack:
|
|
40450
|
+
newPlayer = this.uiFacade.createBackingTrackPlayer();
|
|
40451
|
+
break;
|
|
40452
|
+
case PlayerMode.EnabledExternalMedia:
|
|
40453
|
+
newPlayer = new ExternalMediaPlayer(this.settings.player.bufferTimeInMilliseconds);
|
|
40454
|
+
break;
|
|
40455
|
+
}
|
|
40456
|
+
}
|
|
40457
|
+
else {
|
|
40458
|
+
// no change in player mode, just update song info if needed
|
|
40459
|
+
return true;
|
|
40510
40460
|
}
|
|
40511
40461
|
this.updateCursors();
|
|
40512
40462
|
this._actualPlayerMode = mode;
|
|
40513
|
-
|
|
40514
|
-
case PlayerMode.Disabled:
|
|
40515
|
-
this.destroyPlayer();
|
|
40516
|
-
return false;
|
|
40517
|
-
case PlayerMode.EnabledSynthesizer:
|
|
40518
|
-
if (this.player) {
|
|
40519
|
-
return true;
|
|
40520
|
-
}
|
|
40521
|
-
// new player needed
|
|
40522
|
-
this.player = this.uiFacade.createWorkerPlayer();
|
|
40523
|
-
break;
|
|
40524
|
-
case PlayerMode.EnabledBackingTrack:
|
|
40525
|
-
if (this.player) {
|
|
40526
|
-
return true;
|
|
40527
|
-
}
|
|
40528
|
-
// new player needed
|
|
40529
|
-
this.player = this.uiFacade.createBackingTrackPlayer();
|
|
40530
|
-
break;
|
|
40531
|
-
case PlayerMode.EnabledExternalMedia:
|
|
40532
|
-
if (this.player) {
|
|
40533
|
-
return true;
|
|
40534
|
-
}
|
|
40535
|
-
this.player = new ExternalMediaPlayer(this.settings.player.bufferTimeInMilliseconds);
|
|
40536
|
-
break;
|
|
40537
|
-
}
|
|
40538
|
-
if (!this.player) {
|
|
40463
|
+
if (!newPlayer) {
|
|
40539
40464
|
return false;
|
|
40540
40465
|
}
|
|
40541
|
-
this.
|
|
40542
|
-
this.loadMidiForScore();
|
|
40543
|
-
});
|
|
40544
|
-
this.player.readyForPlayback.on(() => {
|
|
40545
|
-
this.onPlayerReady();
|
|
40546
|
-
if (this.tracks) {
|
|
40547
|
-
for (const track of this.tracks) {
|
|
40548
|
-
const volume = track.playbackInfo.volume / 16;
|
|
40549
|
-
this.player.setChannelVolume(track.playbackInfo.primaryChannel, volume);
|
|
40550
|
-
this.player.setChannelVolume(track.playbackInfo.secondaryChannel, volume);
|
|
40551
|
-
}
|
|
40552
|
-
}
|
|
40553
|
-
});
|
|
40554
|
-
this.player.soundFontLoaded.on(this.onSoundFontLoaded.bind(this));
|
|
40555
|
-
this.player.soundFontLoadFailed.on(e => {
|
|
40556
|
-
this.onError(e);
|
|
40557
|
-
});
|
|
40558
|
-
this.player.midiLoaded.on(this.onMidiLoaded.bind(this));
|
|
40559
|
-
this.player.midiLoadFailed.on(e => {
|
|
40560
|
-
this.onError(e);
|
|
40561
|
-
});
|
|
40562
|
-
this.player.stateChanged.on(this.onPlayerStateChanged.bind(this));
|
|
40563
|
-
this.player.positionChanged.on(this.onPlayerPositionChanged.bind(this));
|
|
40564
|
-
this.player.midiEventsPlayed.on(this.onMidiEventsPlayed.bind(this));
|
|
40565
|
-
this.player.playbackRangeChanged.on(this.onPlaybackRangeChanged.bind(this));
|
|
40566
|
-
this.player.finished.on(this.onPlayerFinished.bind(this));
|
|
40567
|
-
this.setupPlayerEvents();
|
|
40466
|
+
this._player.instance = newPlayer;
|
|
40568
40467
|
return false;
|
|
40569
40468
|
}
|
|
40570
40469
|
loadMidiForScore() {
|
|
@@ -40584,12 +40483,10 @@ class AlphaTabApiBase {
|
|
|
40584
40483
|
generator.generate();
|
|
40585
40484
|
this._tickCache = generator.tickLookup;
|
|
40586
40485
|
this.onMidiLoad(midiFile);
|
|
40587
|
-
const player = this.
|
|
40588
|
-
|
|
40589
|
-
|
|
40590
|
-
|
|
40591
|
-
player.applyTranspositionPitches(generator.transpositionPitches);
|
|
40592
|
-
}
|
|
40486
|
+
const player = this._player;
|
|
40487
|
+
player.loadMidiFile(midiFile);
|
|
40488
|
+
player.loadBackingTrack(score, generator.syncPoints);
|
|
40489
|
+
player.applyTranspositionPitches(generator.transpositionPitches);
|
|
40593
40490
|
}
|
|
40594
40491
|
/**
|
|
40595
40492
|
* Changes the volume of the given tracks.
|
|
@@ -40627,12 +40524,9 @@ class AlphaTabApiBase {
|
|
|
40627
40524
|
* ```
|
|
40628
40525
|
*/
|
|
40629
40526
|
changeTrackVolume(tracks, volume) {
|
|
40630
|
-
if (!this.player) {
|
|
40631
|
-
return;
|
|
40632
|
-
}
|
|
40633
40527
|
for (const track of tracks) {
|
|
40634
|
-
this.
|
|
40635
|
-
this.
|
|
40528
|
+
this._player.setChannelVolume(track.playbackInfo.primaryChannel, volume);
|
|
40529
|
+
this._player.setChannelVolume(track.playbackInfo.secondaryChannel, volume);
|
|
40636
40530
|
}
|
|
40637
40531
|
}
|
|
40638
40532
|
/**
|
|
@@ -40669,12 +40563,9 @@ class AlphaTabApiBase {
|
|
|
40669
40563
|
* ```
|
|
40670
40564
|
*/
|
|
40671
40565
|
changeTrackSolo(tracks, solo) {
|
|
40672
|
-
if (!this.player) {
|
|
40673
|
-
return;
|
|
40674
|
-
}
|
|
40675
40566
|
for (const track of tracks) {
|
|
40676
|
-
this.
|
|
40677
|
-
this.
|
|
40567
|
+
this._player.setChannelSolo(track.playbackInfo.primaryChannel, solo);
|
|
40568
|
+
this._player.setChannelSolo(track.playbackInfo.secondaryChannel, solo);
|
|
40678
40569
|
}
|
|
40679
40570
|
}
|
|
40680
40571
|
/**
|
|
@@ -40710,12 +40601,9 @@ class AlphaTabApiBase {
|
|
|
40710
40601
|
* ```
|
|
40711
40602
|
*/
|
|
40712
40603
|
changeTrackMute(tracks, mute) {
|
|
40713
|
-
if (!this.player) {
|
|
40714
|
-
return;
|
|
40715
|
-
}
|
|
40716
40604
|
for (const track of tracks) {
|
|
40717
|
-
this.
|
|
40718
|
-
this.
|
|
40605
|
+
this._player.setChannelMute(track.playbackInfo.primaryChannel, mute);
|
|
40606
|
+
this._player.setChannelMute(track.playbackInfo.secondaryChannel, mute);
|
|
40719
40607
|
}
|
|
40720
40608
|
}
|
|
40721
40609
|
/**
|
|
@@ -40753,12 +40641,9 @@ class AlphaTabApiBase {
|
|
|
40753
40641
|
* ```
|
|
40754
40642
|
*/
|
|
40755
40643
|
changeTrackTranspositionPitch(tracks, semitones) {
|
|
40756
|
-
if (!this.player) {
|
|
40757
|
-
return;
|
|
40758
|
-
}
|
|
40759
40644
|
for (const track of tracks) {
|
|
40760
|
-
this.
|
|
40761
|
-
this.
|
|
40645
|
+
this._player.setChannelTranspositionPitch(track.playbackInfo.primaryChannel, semitones);
|
|
40646
|
+
this._player.setChannelTranspositionPitch(track.playbackInfo.secondaryChannel, semitones);
|
|
40762
40647
|
}
|
|
40763
40648
|
}
|
|
40764
40649
|
/**
|
|
@@ -40789,10 +40674,7 @@ class AlphaTabApiBase {
|
|
|
40789
40674
|
* ```
|
|
40790
40675
|
*/
|
|
40791
40676
|
play() {
|
|
40792
|
-
|
|
40793
|
-
return false;
|
|
40794
|
-
}
|
|
40795
|
-
return this.player.play();
|
|
40677
|
+
return this._player.play();
|
|
40796
40678
|
}
|
|
40797
40679
|
/**
|
|
40798
40680
|
* Pauses the playback of the current song.
|
|
@@ -40821,10 +40703,7 @@ class AlphaTabApiBase {
|
|
|
40821
40703
|
* ```
|
|
40822
40704
|
*/
|
|
40823
40705
|
pause() {
|
|
40824
|
-
|
|
40825
|
-
return;
|
|
40826
|
-
}
|
|
40827
|
-
this.player.pause();
|
|
40706
|
+
this._player.pause();
|
|
40828
40707
|
}
|
|
40829
40708
|
/**
|
|
40830
40709
|
* Toggles between play/pause depending on the current player state.
|
|
@@ -40855,10 +40734,7 @@ class AlphaTabApiBase {
|
|
|
40855
40734
|
* ```
|
|
40856
40735
|
*/
|
|
40857
40736
|
playPause() {
|
|
40858
|
-
|
|
40859
|
-
return;
|
|
40860
|
-
}
|
|
40861
|
-
this.player.playPause();
|
|
40737
|
+
this._player.playPause();
|
|
40862
40738
|
}
|
|
40863
40739
|
/**
|
|
40864
40740
|
* Stops the playback of the current song, and moves the playback position back to the start.
|
|
@@ -40889,10 +40765,7 @@ class AlphaTabApiBase {
|
|
|
40889
40765
|
* ```
|
|
40890
40766
|
*/
|
|
40891
40767
|
stop() {
|
|
40892
|
-
|
|
40893
|
-
return;
|
|
40894
|
-
}
|
|
40895
|
-
this.player.stop();
|
|
40768
|
+
this._player.stop();
|
|
40896
40769
|
}
|
|
40897
40770
|
/**
|
|
40898
40771
|
* Triggers the play of the given beat.
|
|
@@ -40928,15 +40801,12 @@ class AlphaTabApiBase {
|
|
|
40928
40801
|
* ```
|
|
40929
40802
|
*/
|
|
40930
40803
|
playBeat(beat) {
|
|
40931
|
-
if (!this.player) {
|
|
40932
|
-
return;
|
|
40933
|
-
}
|
|
40934
40804
|
// we generate a new midi file containing only the beat
|
|
40935
40805
|
const midiFile = new MidiFile();
|
|
40936
40806
|
const handler = new AlphaSynthMidiFileHandler(midiFile);
|
|
40937
40807
|
const generator = new MidiFileGenerator(beat.voice.bar.staff.track.score, this.settings, handler);
|
|
40938
40808
|
generator.generateSingleBeat(beat);
|
|
40939
|
-
this.
|
|
40809
|
+
this._player.playOneTimeMidiFile(midiFile);
|
|
40940
40810
|
}
|
|
40941
40811
|
/**
|
|
40942
40812
|
* Triggers the play of the given note.
|
|
@@ -40971,15 +40841,12 @@ class AlphaTabApiBase {
|
|
|
40971
40841
|
* ```
|
|
40972
40842
|
*/
|
|
40973
40843
|
playNote(note) {
|
|
40974
|
-
if (!this.player) {
|
|
40975
|
-
return;
|
|
40976
|
-
}
|
|
40977
40844
|
// we generate a new midi file containing only the beat
|
|
40978
40845
|
const midiFile = new MidiFile();
|
|
40979
40846
|
const handler = new AlphaSynthMidiFileHandler(midiFile);
|
|
40980
40847
|
const generator = new MidiFileGenerator(note.beat.voice.bar.staff.track.score, this.settings, handler);
|
|
40981
40848
|
generator.generateSingleNote(note);
|
|
40982
|
-
this.
|
|
40849
|
+
this._player.playOneTimeMidiFile(midiFile);
|
|
40983
40850
|
}
|
|
40984
40851
|
destroyCursors() {
|
|
40985
40852
|
if (!this._cursorWrapper) {
|
|
@@ -41011,36 +40878,6 @@ class AlphaTabApiBase {
|
|
|
41011
40878
|
this.destroyCursors();
|
|
41012
40879
|
}
|
|
41013
40880
|
}
|
|
41014
|
-
setupPlayerEvents() {
|
|
41015
|
-
//
|
|
41016
|
-
// Hook into events
|
|
41017
|
-
this._previousTick = 0;
|
|
41018
|
-
this._playerState = PlayerState.Paused;
|
|
41019
|
-
// we need to update our position caches if we render a tablature
|
|
41020
|
-
this.renderer.postRenderFinished.on(() => {
|
|
41021
|
-
this._currentBeat = null;
|
|
41022
|
-
this.cursorUpdateTick(this._previousTick, false, 1, this._previousTick > 10);
|
|
41023
|
-
});
|
|
41024
|
-
if (this.player) {
|
|
41025
|
-
this.player.positionChanged.on(e => {
|
|
41026
|
-
this._previousTick = e.currentTick;
|
|
41027
|
-
this.uiFacade.beginInvoke(() => {
|
|
41028
|
-
const cursorSpeed = e.modifiedTempo / e.originalTempo;
|
|
41029
|
-
this.cursorUpdateTick(e.currentTick, false, cursorSpeed, false, e.isSeek);
|
|
41030
|
-
});
|
|
41031
|
-
});
|
|
41032
|
-
this.player.stateChanged.on(e => {
|
|
41033
|
-
this._playerState = e.state;
|
|
41034
|
-
if (!e.stopped && e.state === PlayerState.Paused) {
|
|
41035
|
-
const currentBeat = this._currentBeat;
|
|
41036
|
-
const tickCache = this._tickCache;
|
|
41037
|
-
if (currentBeat && tickCache) {
|
|
41038
|
-
this.player.tickPosition = tickCache.getBeatStart(currentBeat.beat);
|
|
41039
|
-
}
|
|
41040
|
-
}
|
|
41041
|
-
});
|
|
41042
|
-
}
|
|
41043
|
-
}
|
|
41044
40881
|
/**
|
|
41045
40882
|
* updates the cursors to highlight the beat at the specified tick position
|
|
41046
40883
|
* @param tick
|
|
@@ -41081,7 +40918,7 @@ class AlphaTabApiBase {
|
|
|
41081
40918
|
if (!forceUpdate &&
|
|
41082
40919
|
beat === previousBeat?.beat &&
|
|
41083
40920
|
cache === previousCache &&
|
|
41084
|
-
previousState === this.
|
|
40921
|
+
previousState === this._player.state &&
|
|
41085
40922
|
previousBeat?.start === lookupResult.start) {
|
|
41086
40923
|
return;
|
|
41087
40924
|
}
|
|
@@ -41093,7 +40930,7 @@ class AlphaTabApiBase {
|
|
|
41093
40930
|
// actually show the cursor
|
|
41094
40931
|
this._currentBeat = lookupResult;
|
|
41095
40932
|
this._previousCursorCache = cache;
|
|
41096
|
-
this._previousStateForCursor = this.
|
|
40933
|
+
this._previousStateForCursor = this._player.state;
|
|
41097
40934
|
this.uiFacade.beginInvoke(() => {
|
|
41098
40935
|
this.internalCursorUpdateBeat(beat, nextBeat, duration, stop, beatsToHighlight, cache, beatBoundings, shouldScroll, lookupResult.cursorMode, cursorSpeed);
|
|
41099
40936
|
});
|
|
@@ -41104,9 +40941,9 @@ class AlphaTabApiBase {
|
|
|
41104
40941
|
* @category Methods - Player
|
|
41105
40942
|
*/
|
|
41106
40943
|
scrollToCursor() {
|
|
41107
|
-
const
|
|
41108
|
-
if (
|
|
41109
|
-
this.internalScrollToCursor(barBounds);
|
|
40944
|
+
const beatBounds = this._currentBeatBounds;
|
|
40945
|
+
if (beatBounds) {
|
|
40946
|
+
this.internalScrollToCursor(beatBounds.barBounds.masterBarBounds);
|
|
41110
40947
|
}
|
|
41111
40948
|
}
|
|
41112
40949
|
internalScrollToCursor(barBoundings) {
|
|
@@ -41165,10 +41002,12 @@ class AlphaTabApiBase {
|
|
|
41165
41002
|
const beatCursor = this._beatCursor;
|
|
41166
41003
|
const barBoundings = beatBoundings.barBounds.masterBarBounds;
|
|
41167
41004
|
const barBounds = barBoundings.visualBounds;
|
|
41168
|
-
|
|
41005
|
+
const previousBeatBounds = this._currentBeatBounds;
|
|
41006
|
+
this._currentBeatBounds = beatBoundings;
|
|
41169
41007
|
if (barCursor) {
|
|
41170
41008
|
barCursor.setBounds(barBounds.x, barBounds.y, barBounds.w, barBounds.h);
|
|
41171
41009
|
}
|
|
41010
|
+
const isPlayingUpdate = this._player.state === PlayerState.Playing && !stop;
|
|
41172
41011
|
let nextBeatX = barBoundings.visualBounds.x + barBoundings.visualBounds.w;
|
|
41173
41012
|
// get position of next beat on same system
|
|
41174
41013
|
if (nextBeat && cursorMode === MidiTickLookupFindBeatResultCursorMode.ToNextBext) {
|
|
@@ -41186,12 +41025,38 @@ class AlphaTabApiBase {
|
|
|
41186
41025
|
if (this.settings.player.enableAnimatedBeatCursor) {
|
|
41187
41026
|
const animationWidth = nextBeatX - beatBoundings.onNotesX;
|
|
41188
41027
|
const relativePosition = this._previousTick - this._currentBeat.start;
|
|
41189
|
-
const ratioPosition = relativePosition / this._currentBeat.tickDuration;
|
|
41028
|
+
const ratioPosition = this._currentBeat.tickDuration > 0 ? relativePosition / this._currentBeat.tickDuration : 0;
|
|
41190
41029
|
startBeatX = beatBoundings.onNotesX + animationWidth * ratioPosition;
|
|
41191
41030
|
duration -= duration * ratioPosition;
|
|
41192
|
-
|
|
41031
|
+
if (isPlayingUpdate) {
|
|
41032
|
+
// we do not "reset" the cursor if we are smoothly moving from left to right.
|
|
41033
|
+
const jumpCursor = !previousBeatBounds ||
|
|
41034
|
+
barBounds.y !== previousBeatBounds.barBounds.masterBarBounds.visualBounds.y ||
|
|
41035
|
+
startBeatX < previousBeatBounds.onNotesX ||
|
|
41036
|
+
barBoundings.index > previousBeatBounds.barBounds.masterBarBounds.index + 1;
|
|
41037
|
+
if (jumpCursor) {
|
|
41038
|
+
beatCursor.transitionToX(0, startBeatX);
|
|
41039
|
+
beatCursor.setBounds(startBeatX, barBounds.y, 1, barBounds.h);
|
|
41040
|
+
}
|
|
41041
|
+
// we need to put the transition to an own animation frame
|
|
41042
|
+
// otherwise the stop animation above is not applied.
|
|
41043
|
+
this.uiFacade.beginInvoke(() => {
|
|
41044
|
+
// it can happen that the cursor reaches the target position slightly too early (especially on backing tracks)
|
|
41045
|
+
// to avoid the cursor stopping, causing a wierd look, we animate the cursor to the double position in double time.
|
|
41046
|
+
// beatCursor!.transitionToX((duration / cursorSpeed), nextBeatX);
|
|
41047
|
+
const doubleEndBeatX = startBeatX + (nextBeatX - startBeatX) * 2;
|
|
41048
|
+
beatCursor.transitionToX((duration / cursorSpeed) * 2, doubleEndBeatX);
|
|
41049
|
+
});
|
|
41050
|
+
}
|
|
41051
|
+
else {
|
|
41052
|
+
beatCursor.transitionToX(0, startBeatX);
|
|
41053
|
+
beatCursor.setBounds(startBeatX, barBounds.y, 1, barBounds.h);
|
|
41054
|
+
}
|
|
41055
|
+
}
|
|
41056
|
+
else {
|
|
41057
|
+
// ticking cursor
|
|
41058
|
+
beatCursor.setBounds(startBeatX, barBounds.y, 1, barBounds.h);
|
|
41193
41059
|
}
|
|
41194
|
-
beatCursor.setBounds(startBeatX, barBounds.y, 1, barBounds.h);
|
|
41195
41060
|
}
|
|
41196
41061
|
// if playing, animate the cursor to the next beat
|
|
41197
41062
|
if (this.settings.player.enableElementHighlighting) {
|
|
@@ -41199,7 +41064,6 @@ class AlphaTabApiBase {
|
|
|
41199
41064
|
}
|
|
41200
41065
|
// actively playing? -> animate cursor and highlight items
|
|
41201
41066
|
let shouldNotifyBeatChange = false;
|
|
41202
|
-
const isPlayingUpdate = this._playerState === PlayerState.Playing && !stop;
|
|
41203
41067
|
if (isPlayingUpdate) {
|
|
41204
41068
|
if (this.settings.player.enableElementHighlighting) {
|
|
41205
41069
|
for (const highlight of beatsToHighlight) {
|
|
@@ -41210,15 +41074,6 @@ class AlphaTabApiBase {
|
|
|
41210
41074
|
shouldScroll = !stop;
|
|
41211
41075
|
shouldNotifyBeatChange = true;
|
|
41212
41076
|
}
|
|
41213
|
-
if (this.settings.player.enableAnimatedBeatCursor && beatCursor) {
|
|
41214
|
-
if (isPlayingUpdate) {
|
|
41215
|
-
// we need to put the transition to an own animation frame
|
|
41216
|
-
// otherwise the stop animation above is not applied.
|
|
41217
|
-
this.uiFacade.beginInvoke(() => {
|
|
41218
|
-
beatCursor.transitionToX(duration / cursorSpeed, nextBeatX);
|
|
41219
|
-
});
|
|
41220
|
-
}
|
|
41221
|
-
}
|
|
41222
41077
|
if (shouldScroll && !this._beatMouseDown && this.settings.player.scrollMode !== ScrollMode.Off) {
|
|
41223
41078
|
this.internalScrollToCursor(barBoundings);
|
|
41224
41079
|
}
|
|
@@ -41308,7 +41163,7 @@ class AlphaTabApiBase {
|
|
|
41308
41163
|
const realMasterBarStart = tickCache.getMasterBarStart(this._selectionStart.beat.voice.bar.masterBar);
|
|
41309
41164
|
// move to selection start
|
|
41310
41165
|
this._currentBeat = null; // reset current beat so it is updating the cursor
|
|
41311
|
-
if (this.
|
|
41166
|
+
if (this._player.state === PlayerState.Paused) {
|
|
41312
41167
|
this.cursorUpdateTick(this._tickCache.getBeatStart(this._selectionStart.beat), false, 1);
|
|
41313
41168
|
}
|
|
41314
41169
|
this.tickPosition = realMasterBarStart + this._selectionStart.beat.playbackStart;
|
|
@@ -41499,7 +41354,7 @@ class AlphaTabApiBase {
|
|
|
41499
41354
|
}
|
|
41500
41355
|
this.scoreLoaded.trigger(score);
|
|
41501
41356
|
this.uiFacade.triggerEvent(this.container, 'scoreLoaded', score);
|
|
41502
|
-
if (this.
|
|
41357
|
+
if (this.setupOrDestroyPlayer()) {
|
|
41503
41358
|
this.loadMidiForScore();
|
|
41504
41359
|
}
|
|
41505
41360
|
}
|
|
@@ -41528,6 +41383,8 @@ class AlphaTabApiBase {
|
|
|
41528
41383
|
if (this._isDestroyed) {
|
|
41529
41384
|
return;
|
|
41530
41385
|
}
|
|
41386
|
+
this._currentBeat = null;
|
|
41387
|
+
this.cursorUpdateTick(this._previousTick, false, 1, this._previousTick > 10);
|
|
41531
41388
|
this.postRenderFinished.trigger();
|
|
41532
41389
|
this.uiFacade.triggerEvent(this.container, 'postRenderFinished', null);
|
|
41533
41390
|
}
|
|
@@ -41542,25 +41399,155 @@ class AlphaTabApiBase {
|
|
|
41542
41399
|
this.error.trigger(error);
|
|
41543
41400
|
this.uiFacade.triggerEvent(this.container, 'error', error);
|
|
41544
41401
|
}
|
|
41402
|
+
/**
|
|
41403
|
+
* This event is fired when all required data for playback is loaded and ready.
|
|
41404
|
+
* @remarks
|
|
41405
|
+
* This event is fired when all required data for playback is loaded and ready. The player is ready for playback when
|
|
41406
|
+
* 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.
|
|
41407
|
+
*
|
|
41408
|
+
* @eventProperty
|
|
41409
|
+
* @category Events - Player
|
|
41410
|
+
* @since 0.9.4
|
|
41411
|
+
*
|
|
41412
|
+
* @example
|
|
41413
|
+
* JavaScript
|
|
41414
|
+
* ```js
|
|
41415
|
+
* const api = new alphaTab.AlphaTabApi(document.querySelector('#alphaTab'));
|
|
41416
|
+
* api.playerReady.on(() => {
|
|
41417
|
+
* enablePlayerControls();
|
|
41418
|
+
* });
|
|
41419
|
+
* ```
|
|
41420
|
+
*
|
|
41421
|
+
* @example
|
|
41422
|
+
* C#
|
|
41423
|
+
* ```cs
|
|
41424
|
+
* var api = new AlphaTabApi<MyControl>(...);
|
|
41425
|
+
* api.PlayerReady.On(() =>
|
|
41426
|
+
* {
|
|
41427
|
+
* EnablePlayerControls()
|
|
41428
|
+
* });
|
|
41429
|
+
* ```
|
|
41430
|
+
*
|
|
41431
|
+
* @example
|
|
41432
|
+
* Android
|
|
41433
|
+
* ```kotlin
|
|
41434
|
+
* val api = AlphaTabApi<MyControl>(...)
|
|
41435
|
+
* api.playerReady.on {
|
|
41436
|
+
* enablePlayerControls()
|
|
41437
|
+
* }
|
|
41438
|
+
* ```
|
|
41439
|
+
*/
|
|
41440
|
+
get playerReady() {
|
|
41441
|
+
return this._player.readyForPlayback;
|
|
41442
|
+
}
|
|
41545
41443
|
onPlayerReady() {
|
|
41546
41444
|
if (this._isDestroyed) {
|
|
41547
41445
|
return;
|
|
41548
41446
|
}
|
|
41549
|
-
this.playerReady.trigger();
|
|
41550
41447
|
this.uiFacade.triggerEvent(this.container, 'playerReady', null);
|
|
41551
41448
|
}
|
|
41449
|
+
/**
|
|
41450
|
+
* This event is fired when the playback of the whole song finished.
|
|
41451
|
+
* @remarks
|
|
41452
|
+
* This event is finished regardless on whether looping is enabled or not.
|
|
41453
|
+
*
|
|
41454
|
+
* @eventProperty
|
|
41455
|
+
* @category Events - Player
|
|
41456
|
+
* @since 0.9.4
|
|
41457
|
+
*
|
|
41458
|
+
* @example
|
|
41459
|
+
* JavaScript
|
|
41460
|
+
* ```js
|
|
41461
|
+
* const api = new alphaTab.AlphaTabApi(document.querySelector('#alphaTab'));
|
|
41462
|
+
* api.playerFinished.on((args) => {
|
|
41463
|
+
* // speed trainer
|
|
41464
|
+
* api.playbackSpeed = Math.min(1.0, api.playbackSpeed + 0.1);
|
|
41465
|
+
* });
|
|
41466
|
+
* api.isLooping = true;
|
|
41467
|
+
* api.playbackSpeed = 0.5;
|
|
41468
|
+
* api.play()
|
|
41469
|
+
* ```
|
|
41470
|
+
*
|
|
41471
|
+
* @example
|
|
41472
|
+
* C#
|
|
41473
|
+
* ```cs
|
|
41474
|
+
* var api = new AlphaTabApi<MyControl>(...);
|
|
41475
|
+
* api.PlayerFinished.On(() =>
|
|
41476
|
+
* {
|
|
41477
|
+
* // speed trainer
|
|
41478
|
+
* api.PlaybackSpeed = Math.Min(1.0, api.PlaybackSpeed + 0.1);
|
|
41479
|
+
* });
|
|
41480
|
+
* api.IsLooping = true;
|
|
41481
|
+
* api.PlaybackSpeed = 0.5;
|
|
41482
|
+
* api.Play();
|
|
41483
|
+
* ```
|
|
41484
|
+
*
|
|
41485
|
+
* @example
|
|
41486
|
+
* Android
|
|
41487
|
+
* ```kotlin
|
|
41488
|
+
* val api = AlphaTabApi<MyControl>(...)
|
|
41489
|
+
* api.playerFinished.on {
|
|
41490
|
+
* // speed trainer
|
|
41491
|
+
* api.playbackSpeed = min(1.0, api.playbackSpeed + 0.1);
|
|
41492
|
+
* }
|
|
41493
|
+
* api.isLooping = true
|
|
41494
|
+
* api.playbackSpeed = 0.5
|
|
41495
|
+
* api.play()
|
|
41496
|
+
* ```
|
|
41497
|
+
*
|
|
41498
|
+
*/
|
|
41499
|
+
get playerFinished() {
|
|
41500
|
+
return this._player.finished;
|
|
41501
|
+
}
|
|
41552
41502
|
onPlayerFinished() {
|
|
41553
41503
|
if (this._isDestroyed) {
|
|
41554
41504
|
return;
|
|
41555
41505
|
}
|
|
41556
|
-
this.playerFinished.trigger();
|
|
41557
41506
|
this.uiFacade.triggerEvent(this.container, 'playerFinished', null);
|
|
41558
41507
|
}
|
|
41508
|
+
/**
|
|
41509
|
+
* This event is fired when the SoundFont needed for playback was loaded.
|
|
41510
|
+
*
|
|
41511
|
+
* @eventProperty
|
|
41512
|
+
* @category Events - Player
|
|
41513
|
+
* @since 0.9.4
|
|
41514
|
+
*
|
|
41515
|
+
* @example
|
|
41516
|
+
* JavaScript
|
|
41517
|
+
* ```js
|
|
41518
|
+
* const api = new alphaTab.AlphaTabApi(document.querySelector('#alphaTab'));
|
|
41519
|
+
* api.soundFontLoaded.on(() => {
|
|
41520
|
+
* hideSoundFontLoadingIndicator();
|
|
41521
|
+
* });
|
|
41522
|
+
* ```
|
|
41523
|
+
*
|
|
41524
|
+
* @example
|
|
41525
|
+
* C#
|
|
41526
|
+
* ```cs
|
|
41527
|
+
* var api = new AlphaTabApi<MyControl>(...);
|
|
41528
|
+
* api.SoundFontLoaded.On(() =>
|
|
41529
|
+
* {
|
|
41530
|
+
* HideSoundFontLoadingIndicator();
|
|
41531
|
+
* });
|
|
41532
|
+
* ```
|
|
41533
|
+
*
|
|
41534
|
+
* @example
|
|
41535
|
+
* Android
|
|
41536
|
+
* ```kotlin
|
|
41537
|
+
* val api = AlphaTabApi<MyControl>(...);
|
|
41538
|
+
* api.soundFontLoaded.on {
|
|
41539
|
+
* hideSoundFontLoadingIndicator();
|
|
41540
|
+
* }
|
|
41541
|
+
* ```
|
|
41542
|
+
*
|
|
41543
|
+
*/
|
|
41544
|
+
get soundFontLoaded() {
|
|
41545
|
+
return this._player.soundFontLoaded;
|
|
41546
|
+
}
|
|
41559
41547
|
onSoundFontLoaded() {
|
|
41560
41548
|
if (this._isDestroyed) {
|
|
41561
41549
|
return;
|
|
41562
41550
|
}
|
|
41563
|
-
this.soundFontLoaded.trigger();
|
|
41564
41551
|
this.uiFacade.triggerEvent(this.container, 'soundFontLoaded', null);
|
|
41565
41552
|
}
|
|
41566
41553
|
onMidiLoad(e) {
|
|
@@ -41577,34 +41564,255 @@ class AlphaTabApiBase {
|
|
|
41577
41564
|
this.midiLoaded.trigger(e);
|
|
41578
41565
|
this.uiFacade.triggerEvent(this.container, 'midiFileLoaded', e);
|
|
41579
41566
|
}
|
|
41567
|
+
/**
|
|
41568
|
+
* This event is fired when the playback state changed.
|
|
41569
|
+
*
|
|
41570
|
+
* @eventProperty
|
|
41571
|
+
* @category Events - Player
|
|
41572
|
+
* @since 0.9.4
|
|
41573
|
+
*
|
|
41574
|
+
* @example
|
|
41575
|
+
* JavaScript
|
|
41576
|
+
* ```js
|
|
41577
|
+
* const api = new alphaTab.AlphaTabApi(document.querySelector('#alphaTab'));
|
|
41578
|
+
* api.playerStateChanged.on((args) => {
|
|
41579
|
+
* updatePlayerControls(args.state, args.stopped);
|
|
41580
|
+
* });
|
|
41581
|
+
* ```
|
|
41582
|
+
*
|
|
41583
|
+
* @example
|
|
41584
|
+
* C#
|
|
41585
|
+
* ```cs
|
|
41586
|
+
* var api = new AlphaTabApi<MyControl>(...);
|
|
41587
|
+
* api.PlayerStateChanged.On(args =>
|
|
41588
|
+
* {
|
|
41589
|
+
* UpdatePlayerControls(args);
|
|
41590
|
+
* });
|
|
41591
|
+
* ```
|
|
41592
|
+
*
|
|
41593
|
+
* @example
|
|
41594
|
+
* Android
|
|
41595
|
+
* ```kotlin
|
|
41596
|
+
* val api = AlphaTabApi<MyControl>(...)
|
|
41597
|
+
* api.playerStateChanged.on { args ->
|
|
41598
|
+
* updatePlayerControls(args)
|
|
41599
|
+
* }
|
|
41600
|
+
* ```
|
|
41601
|
+
*
|
|
41602
|
+
*/
|
|
41603
|
+
get playerStateChanged() {
|
|
41604
|
+
return this._player.stateChanged;
|
|
41605
|
+
}
|
|
41580
41606
|
onPlayerStateChanged(e) {
|
|
41581
41607
|
if (this._isDestroyed) {
|
|
41582
41608
|
return;
|
|
41583
41609
|
}
|
|
41584
|
-
|
|
41610
|
+
if (!e.stopped && e.state === PlayerState.Paused) {
|
|
41611
|
+
const currentBeat = this._currentBeat;
|
|
41612
|
+
const tickCache = this._tickCache;
|
|
41613
|
+
if (currentBeat && tickCache) {
|
|
41614
|
+
this._player.tickPosition = tickCache.getBeatStart(currentBeat.beat);
|
|
41615
|
+
}
|
|
41616
|
+
}
|
|
41585
41617
|
this.uiFacade.triggerEvent(this.container, 'playerStateChanged', e);
|
|
41586
41618
|
}
|
|
41619
|
+
/**
|
|
41620
|
+
* This event is fired when the current playback position of the song changed.
|
|
41621
|
+
*
|
|
41622
|
+
* @eventProperty
|
|
41623
|
+
* @category Events - Player
|
|
41624
|
+
* @since 0.9.4
|
|
41625
|
+
*
|
|
41626
|
+
* @example
|
|
41627
|
+
* JavaScript
|
|
41628
|
+
* ```js
|
|
41629
|
+
* const api = new alphaTab.AlphaTabApi(document.querySelector('#alphaTab'));
|
|
41630
|
+
* api.playerPositionChanged.on((args) => {
|
|
41631
|
+
* updatePlayerPosition(args);
|
|
41632
|
+
* });
|
|
41633
|
+
* ```
|
|
41634
|
+
*
|
|
41635
|
+
* @example
|
|
41636
|
+
* C#
|
|
41637
|
+
* ```cs
|
|
41638
|
+
* var api = new AlphaTabApi<MyControl>(...);
|
|
41639
|
+
* api.PlayerPositionChanged.On(args =>
|
|
41640
|
+
* {
|
|
41641
|
+
* UpdatePlayerPosition(args);
|
|
41642
|
+
* });
|
|
41643
|
+
* ```
|
|
41644
|
+
*
|
|
41645
|
+
* @example
|
|
41646
|
+
* Android
|
|
41647
|
+
* ```kotlin
|
|
41648
|
+
* val api = AlphaTabApi<MyControl>(...)
|
|
41649
|
+
* api.playerPositionChanged.on { args ->
|
|
41650
|
+
* updatePlayerPosition(args)
|
|
41651
|
+
* }
|
|
41652
|
+
* ```
|
|
41653
|
+
*
|
|
41654
|
+
*/
|
|
41655
|
+
get playerPositionChanged() {
|
|
41656
|
+
return this._player.positionChanged;
|
|
41657
|
+
}
|
|
41587
41658
|
onPlayerPositionChanged(e) {
|
|
41588
41659
|
if (this._isDestroyed) {
|
|
41589
41660
|
return;
|
|
41590
41661
|
}
|
|
41591
|
-
|
|
41592
|
-
|
|
41593
|
-
|
|
41594
|
-
|
|
41662
|
+
this._previousTick = e.currentTick;
|
|
41663
|
+
this.uiFacade.beginInvoke(() => {
|
|
41664
|
+
const cursorSpeed = e.modifiedTempo / e.originalTempo;
|
|
41665
|
+
this.cursorUpdateTick(e.currentTick, false, cursorSpeed, false, e.isSeek);
|
|
41666
|
+
});
|
|
41667
|
+
this.uiFacade.triggerEvent(this.container, 'playerPositionChanged', e);
|
|
41668
|
+
}
|
|
41669
|
+
/**
|
|
41670
|
+
* This event is fired when the synthesizer played certain midi events.
|
|
41671
|
+
*
|
|
41672
|
+
* @remarks
|
|
41673
|
+
* This event is fired when the synthesizer played certain midi events. This allows reacing on various low level
|
|
41674
|
+
* audio playback elements like notes/rests played or metronome ticks.
|
|
41675
|
+
*
|
|
41676
|
+
* Refer to the [related guide](https://www.alphatab.net/docs/guides/handling-midi-events) to learn more about this feature.
|
|
41677
|
+
*
|
|
41678
|
+
* Also note that the provided data models changed significantly in {@version 1.3.0}. We try to provide backwards compatibility
|
|
41679
|
+
* until some extend but highly encourage changing to the new models in case of problems.
|
|
41680
|
+
*
|
|
41681
|
+
* @eventProperty
|
|
41682
|
+
* @category Events - Player
|
|
41683
|
+
* @since 1.2.0
|
|
41684
|
+
*
|
|
41685
|
+
* @example
|
|
41686
|
+
* JavaScript
|
|
41687
|
+
* ```js
|
|
41688
|
+
* const api = new alphaTab.AlphaTabApi(document.querySelector('#alphaTab'));
|
|
41689
|
+
* api.midiEventsPlayedFilter = [alphaTab.midi.MidiEventType.AlphaTabMetronome];
|
|
41690
|
+
* api.midiEventsPlayed.on(function(e) {
|
|
41691
|
+
* for(const midi of e.events) {
|
|
41692
|
+
* if(midi.isMetronome) {
|
|
41693
|
+
* console.log('Metronome tick ' + midi.tick);
|
|
41694
|
+
* }
|
|
41695
|
+
* }
|
|
41696
|
+
* });
|
|
41697
|
+
* ```
|
|
41698
|
+
*
|
|
41699
|
+
* @example
|
|
41700
|
+
* C#
|
|
41701
|
+
* ```cs
|
|
41702
|
+
* var api = new AlphaTabApi<MyControl>(...);
|
|
41703
|
+
* api.MidiEventsPlayedFilter = new MidiEventType[] { AlphaTab.Midi.MidiEventType.AlphaTabMetronome };
|
|
41704
|
+
* api.MidiEventsPlayed.On(e =>
|
|
41705
|
+
* {
|
|
41706
|
+
* foreach(var midi of e.events)
|
|
41707
|
+
* {
|
|
41708
|
+
* if(midi is AlphaTab.Midi.AlphaTabMetronomeEvent sysex && sysex.IsMetronome)
|
|
41709
|
+
* {
|
|
41710
|
+
* Console.WriteLine("Metronome tick " + midi.Tick);
|
|
41711
|
+
* }
|
|
41712
|
+
* }
|
|
41713
|
+
* });
|
|
41714
|
+
* ```
|
|
41715
|
+
*
|
|
41716
|
+
* @example
|
|
41717
|
+
* Android
|
|
41718
|
+
* ```kotlin
|
|
41719
|
+
* val api = AlphaTabApi<MyControl>(...);
|
|
41720
|
+
* api.midiEventsPlayedFilter = alphaTab.collections.List<alphaTab.midi.MidiEventType>( alphaTab.midi.MidiEventType.AlphaTabMetronome )
|
|
41721
|
+
* api.midiEventsPlayed.on { e ->
|
|
41722
|
+
* for (midi in e.events) {
|
|
41723
|
+
* if(midi instanceof alphaTab.midi.AlphaTabMetronomeEvent && midi.isMetronome) {
|
|
41724
|
+
* println("Metronome tick " + midi.tick);
|
|
41725
|
+
* }
|
|
41726
|
+
* }
|
|
41727
|
+
* }
|
|
41728
|
+
* ```
|
|
41729
|
+
* @see {@link MidiEvent}
|
|
41730
|
+
* @see {@link TimeSignatureEvent}
|
|
41731
|
+
* @see {@link AlphaTabMetronomeEvent}
|
|
41732
|
+
* @see {@link AlphaTabRestEvent}
|
|
41733
|
+
* @see {@link NoteOnEvent}
|
|
41734
|
+
* @see {@link NoteOffEvent}
|
|
41735
|
+
* @see {@link ControlChangeEvent}
|
|
41736
|
+
* @see {@link ProgramChangeEvent}
|
|
41737
|
+
* @see {@link TempoChangeEvent}
|
|
41738
|
+
* @see {@link PitchBendEvent}
|
|
41739
|
+
* @see {@link NoteBendEvent}
|
|
41740
|
+
* @see {@link EndOfTrackEvent}
|
|
41741
|
+
* @see {@link MetaEvent}
|
|
41742
|
+
* @see {@link MetaDataEvent}
|
|
41743
|
+
* @see {@link MetaNumberEvent}
|
|
41744
|
+
* @see {@link Midi20PerNotePitchBendEvent}
|
|
41745
|
+
* @see {@link SystemCommonEvent}
|
|
41746
|
+
* @see {@link SystemExclusiveEvent}
|
|
41747
|
+
*/
|
|
41748
|
+
get midiEventsPlayed() {
|
|
41749
|
+
return this._player.midiEventsPlayed;
|
|
41595
41750
|
}
|
|
41596
41751
|
onMidiEventsPlayed(e) {
|
|
41597
41752
|
if (this._isDestroyed) {
|
|
41598
41753
|
return;
|
|
41599
41754
|
}
|
|
41600
|
-
this.midiEventsPlayed.trigger(e);
|
|
41601
41755
|
this.uiFacade.triggerEvent(this.container, 'midiEventsPlayed', e);
|
|
41602
41756
|
}
|
|
41757
|
+
/**
|
|
41758
|
+
* This event is fired when the playback range changed.
|
|
41759
|
+
*
|
|
41760
|
+
* @eventProperty
|
|
41761
|
+
* @category Events - Player
|
|
41762
|
+
* @since 1.2.3
|
|
41763
|
+
*
|
|
41764
|
+
* @example
|
|
41765
|
+
* JavaScript
|
|
41766
|
+
* ```js
|
|
41767
|
+
* const api = new alphaTab.AlphaTabApi(document.querySelector('#alphaTab'));
|
|
41768
|
+
* api.playbackRangeChanged.on((args) => {
|
|
41769
|
+
* if (args.playbackRange) {
|
|
41770
|
+
* highlightRangeInProgressBar(args.playbackRange.startTick, args.playbackRange.endTick);
|
|
41771
|
+
* } else {
|
|
41772
|
+
* clearHighlightInProgressBar();
|
|
41773
|
+
* }
|
|
41774
|
+
* });
|
|
41775
|
+
* ```
|
|
41776
|
+
*
|
|
41777
|
+
* @example
|
|
41778
|
+
* C#
|
|
41779
|
+
* ```cs
|
|
41780
|
+
* var api = new AlphaTabApi<MyControl>(...);
|
|
41781
|
+
* api.PlaybackRangeChanged.On(args =>
|
|
41782
|
+
* {
|
|
41783
|
+
* if (args.PlaybackRange != null)
|
|
41784
|
+
* {
|
|
41785
|
+
* HighlightRangeInProgressBar(args.PlaybackRange.StartTick, args.PlaybackRange.EndTick);
|
|
41786
|
+
* }
|
|
41787
|
+
* else
|
|
41788
|
+
* {
|
|
41789
|
+
* ClearHighlightInProgressBar();
|
|
41790
|
+
* }
|
|
41791
|
+
* });
|
|
41792
|
+
* ```
|
|
41793
|
+
*
|
|
41794
|
+
* @example
|
|
41795
|
+
* Android
|
|
41796
|
+
* ```kotlin
|
|
41797
|
+
* val api = AlphaTabApi<MyControl>(...)
|
|
41798
|
+
* api.playbackRangeChanged.on { args ->
|
|
41799
|
+
* val playbackRange = args.playbackRange
|
|
41800
|
+
* if (playbackRange != null) {
|
|
41801
|
+
* highlightRangeInProgressBar(playbackRange.startTick, playbackRange.endTick)
|
|
41802
|
+
* } else {
|
|
41803
|
+
* clearHighlightInProgressBar()
|
|
41804
|
+
* }
|
|
41805
|
+
* }
|
|
41806
|
+
* ```
|
|
41807
|
+
*
|
|
41808
|
+
*/
|
|
41809
|
+
get playbackRangeChanged() {
|
|
41810
|
+
return this._player.playbackRangeChanged;
|
|
41811
|
+
}
|
|
41603
41812
|
onPlaybackRangeChanged(e) {
|
|
41604
41813
|
if (this._isDestroyed) {
|
|
41605
41814
|
return;
|
|
41606
41815
|
}
|
|
41607
|
-
this.playbackRangeChanged.trigger(e);
|
|
41608
41816
|
this.uiFacade.triggerEvent(this.container, 'playbackRangeChanged', e);
|
|
41609
41817
|
}
|
|
41610
41818
|
onSettingsUpdated() {
|
|
@@ -41666,10 +41874,7 @@ class AlphaTabApiBase {
|
|
|
41666
41874
|
* ```
|
|
41667
41875
|
*/
|
|
41668
41876
|
async enumerateOutputDevices() {
|
|
41669
|
-
|
|
41670
|
-
return await this.player.output.enumerateOutputDevices();
|
|
41671
|
-
}
|
|
41672
|
-
return [];
|
|
41877
|
+
return await this._player.output.enumerateOutputDevices();
|
|
41673
41878
|
}
|
|
41674
41879
|
/**
|
|
41675
41880
|
* Changes the output device which should be used for playing the audio (player must be enabled).
|
|
@@ -41720,9 +41925,7 @@ class AlphaTabApiBase {
|
|
|
41720
41925
|
* ```
|
|
41721
41926
|
*/
|
|
41722
41927
|
async setOutputDevice(device) {
|
|
41723
|
-
|
|
41724
|
-
await this.player.output.setOutputDevice(device);
|
|
41725
|
-
}
|
|
41928
|
+
await this._player.output.setOutputDevice(device);
|
|
41726
41929
|
}
|
|
41727
41930
|
/**
|
|
41728
41931
|
* The currently configured output device if changed via {@link setOutputDevice}.
|
|
@@ -41762,10 +41965,7 @@ class AlphaTabApiBase {
|
|
|
41762
41965
|
*
|
|
41763
41966
|
*/
|
|
41764
41967
|
async getOutputDevice() {
|
|
41765
|
-
|
|
41766
|
-
return await this.player.output.getOutputDevice();
|
|
41767
|
-
}
|
|
41768
|
-
return null;
|
|
41968
|
+
return await this._player.output.getOutputDevice();
|
|
41769
41969
|
}
|
|
41770
41970
|
}
|
|
41771
41971
|
|
|
@@ -41942,38 +42142,52 @@ class HtmlElementContainer {
|
|
|
41942
42142
|
this.element = element;
|
|
41943
42143
|
this.mouseDown = {
|
|
41944
42144
|
on: (value) => {
|
|
41945
|
-
|
|
42145
|
+
const nativeListener = e => {
|
|
41946
42146
|
value(new BrowserMouseEventArgs(e));
|
|
41947
|
-
}
|
|
42147
|
+
};
|
|
42148
|
+
this.element.addEventListener('mousedown', nativeListener, true);
|
|
42149
|
+
return () => {
|
|
42150
|
+
this.element.removeEventListener('mousedown', nativeListener, true);
|
|
42151
|
+
};
|
|
41948
42152
|
},
|
|
41949
42153
|
off: (value) => {
|
|
41950
42154
|
}
|
|
41951
42155
|
};
|
|
41952
42156
|
this.mouseUp = {
|
|
41953
42157
|
on: (value) => {
|
|
41954
|
-
|
|
42158
|
+
const nativeListener = e => {
|
|
41955
42159
|
value(new BrowserMouseEventArgs(e));
|
|
41956
|
-
}
|
|
42160
|
+
};
|
|
42161
|
+
this.element.addEventListener('mouseup', nativeListener, true);
|
|
42162
|
+
return () => {
|
|
42163
|
+
this.element.removeEventListener('mouseup', nativeListener, true);
|
|
42164
|
+
};
|
|
41957
42165
|
},
|
|
41958
42166
|
off: (value) => {
|
|
41959
42167
|
}
|
|
41960
42168
|
};
|
|
41961
42169
|
this.mouseMove = {
|
|
41962
42170
|
on: (value) => {
|
|
41963
|
-
|
|
42171
|
+
const nativeListener = e => {
|
|
41964
42172
|
value(new BrowserMouseEventArgs(e));
|
|
41965
|
-
}
|
|
42173
|
+
};
|
|
42174
|
+
this.element.addEventListener('mousemove', nativeListener, true);
|
|
42175
|
+
return () => {
|
|
42176
|
+
this.element.removeEventListener('mousemove', nativeListener, true);
|
|
42177
|
+
};
|
|
41966
42178
|
},
|
|
41967
42179
|
off: (_) => {
|
|
41968
42180
|
}
|
|
41969
42181
|
};
|
|
42182
|
+
const container = this;
|
|
41970
42183
|
this.resize = {
|
|
41971
|
-
on: (value)
|
|
41972
|
-
if (
|
|
41973
|
-
HtmlElementContainer.resizeObserver.value.observe(
|
|
42184
|
+
on: function (value) {
|
|
42185
|
+
if (container._resizeListeners === 0) {
|
|
42186
|
+
HtmlElementContainer.resizeObserver.value.observe(container.element);
|
|
41974
42187
|
}
|
|
41975
|
-
|
|
41976
|
-
|
|
42188
|
+
container.element.addEventListener('resize', value, true);
|
|
42189
|
+
container._resizeListeners++;
|
|
42190
|
+
return () => this.off(value);
|
|
41977
42191
|
},
|
|
41978
42192
|
off: (value) => {
|
|
41979
42193
|
this.element.removeEventListener('resize', value, true);
|
|
@@ -42554,21 +42768,6 @@ class AlphaSynthScriptProcessorOutput extends AlphaSynthWebAudioOutputBase {
|
|
|
42554
42768
|
}
|
|
42555
42769
|
}
|
|
42556
42770
|
|
|
42557
|
-
/**
|
|
42558
|
-
* Represents the progress of any data being loaded.
|
|
42559
|
-
*/
|
|
42560
|
-
class ProgressEventArgs {
|
|
42561
|
-
/**
|
|
42562
|
-
* Initializes a new instance of the {@link ProgressEventArgs} class.
|
|
42563
|
-
* @param loaded
|
|
42564
|
-
* @param total
|
|
42565
|
-
*/
|
|
42566
|
-
constructor(loaded, total) {
|
|
42567
|
-
this.loaded = loaded;
|
|
42568
|
-
this.total = total;
|
|
42569
|
-
}
|
|
42570
|
-
}
|
|
42571
|
-
|
|
42572
42771
|
/**
|
|
42573
42772
|
* a WebWorker based alphaSynth which uses the given player as output.
|
|
42574
42773
|
* @target web
|
|
@@ -42805,25 +43004,6 @@ class AlphaSynthWebWorkerApi {
|
|
|
42805
43004
|
append: append
|
|
42806
43005
|
});
|
|
42807
43006
|
}
|
|
42808
|
-
loadSoundFontFromUrl(url, append, progress) {
|
|
42809
|
-
Logger.debug('AlphaSynth', `Start loading Soundfont from url ${url}`);
|
|
42810
|
-
const request = new XMLHttpRequest();
|
|
42811
|
-
request.open('GET', url, true, null, null);
|
|
42812
|
-
request.responseType = 'arraybuffer';
|
|
42813
|
-
request.onload = _ => {
|
|
42814
|
-
const buffer = new Uint8Array(request.response);
|
|
42815
|
-
this.loadSoundFont(buffer, append);
|
|
42816
|
-
};
|
|
42817
|
-
request.onerror = e => {
|
|
42818
|
-
Logger.error('AlphaSynth', `Loading failed: ${e.message}`);
|
|
42819
|
-
this.soundFontLoadFailed.trigger(new FileLoadError(e.message, request));
|
|
42820
|
-
};
|
|
42821
|
-
request.onprogress = e => {
|
|
42822
|
-
Logger.debug('AlphaSynth', `Soundfont downloading: ${e.loaded}/${e.total} bytes`);
|
|
42823
|
-
progress(new ProgressEventArgs(e.loaded, e.total));
|
|
42824
|
-
};
|
|
42825
|
-
request.send();
|
|
42826
|
-
}
|
|
42827
43007
|
resetSoundFonts() {
|
|
42828
43008
|
this._synth.postMessage({
|
|
42829
43009
|
cmd: 'alphaSynth.resetSoundFonts'
|
|
@@ -43375,7 +43555,11 @@ class AudioElementBackingTrackSynthOutput {
|
|
|
43375
43555
|
}
|
|
43376
43556
|
this._padding = backingTrack.padding / 1000;
|
|
43377
43557
|
const blob = new Blob([backingTrack.rawAudioFile]);
|
|
43558
|
+
// https://html.spec.whatwg.org/multipage/media.html#loading-the-media-resource
|
|
43559
|
+
// Step 8. resets the playbackRate, we need to remember and restore it.
|
|
43560
|
+
const playbackRate = this.audioElement.playbackRate;
|
|
43378
43561
|
this.audioElement.src = URL.createObjectURL(blob);
|
|
43562
|
+
this.audioElement.playbackRate = playbackRate;
|
|
43379
43563
|
}
|
|
43380
43564
|
open(_bufferTimeInMilliseconds) {
|
|
43381
43565
|
const audioElement = document.createElement('audio');
|
|
@@ -44094,6 +44278,21 @@ class BrowserUiFacade {
|
|
|
44094
44278
|
}
|
|
44095
44279
|
}
|
|
44096
44280
|
|
|
44281
|
+
/**
|
|
44282
|
+
* Represents the progress of any data being loaded.
|
|
44283
|
+
*/
|
|
44284
|
+
class ProgressEventArgs {
|
|
44285
|
+
/**
|
|
44286
|
+
* Initializes a new instance of the {@link ProgressEventArgs} class.
|
|
44287
|
+
* @param loaded
|
|
44288
|
+
* @param total
|
|
44289
|
+
*/
|
|
44290
|
+
constructor(loaded, total) {
|
|
44291
|
+
this.loaded = loaded;
|
|
44292
|
+
this.total = total;
|
|
44293
|
+
}
|
|
44294
|
+
}
|
|
44295
|
+
|
|
44097
44296
|
/**
|
|
44098
44297
|
* @target web
|
|
44099
44298
|
*/
|
|
@@ -44337,13 +44536,29 @@ class AlphaTabApi extends AlphaTabApiBase {
|
|
|
44337
44536
|
* @since 0.9.4
|
|
44338
44537
|
*/
|
|
44339
44538
|
loadSoundFontFromUrl(url, append) {
|
|
44340
|
-
|
|
44539
|
+
const player = this.player;
|
|
44540
|
+
if (!player) {
|
|
44341
44541
|
return;
|
|
44342
44542
|
}
|
|
44343
|
-
|
|
44344
|
-
|
|
44345
|
-
|
|
44346
|
-
|
|
44543
|
+
Logger.debug('AlphaSynth', `Start loading Soundfont from url ${url}`);
|
|
44544
|
+
const request = new XMLHttpRequest();
|
|
44545
|
+
request.open('GET', url, true, null, null);
|
|
44546
|
+
request.responseType = 'arraybuffer';
|
|
44547
|
+
request.onload = _ => {
|
|
44548
|
+
const buffer = new Uint8Array(request.response);
|
|
44549
|
+
this.loadSoundFont(buffer, append);
|
|
44550
|
+
};
|
|
44551
|
+
request.onerror = e => {
|
|
44552
|
+
Logger.error('AlphaSynth', `Loading failed: ${e.message}`);
|
|
44553
|
+
player.soundFontLoadFailed.trigger(new FileLoadError(e.message, request));
|
|
44554
|
+
};
|
|
44555
|
+
request.onprogress = e => {
|
|
44556
|
+
Logger.debug('AlphaSynth', `Soundfont downloading: ${e.loaded}/${e.total} bytes`);
|
|
44557
|
+
const args = new ProgressEventArgs(e.loaded, e.total);
|
|
44558
|
+
this.soundFontLoad.trigger(args);
|
|
44559
|
+
this.uiFacade.triggerEvent(this.container, 'soundFontLoad', args);
|
|
44560
|
+
};
|
|
44561
|
+
request.send();
|
|
44347
44562
|
}
|
|
44348
44563
|
}
|
|
44349
44564
|
|
|
@@ -60310,9 +60525,9 @@ class VersionInfo {
|
|
|
60310
60525
|
print(`build date: ${VersionInfo.date}`);
|
|
60311
60526
|
}
|
|
60312
60527
|
}
|
|
60313
|
-
VersionInfo.version = '1.6.0-alpha.
|
|
60314
|
-
VersionInfo.date = '2025-05-
|
|
60315
|
-
VersionInfo.commit = '
|
|
60528
|
+
VersionInfo.version = '1.6.0-alpha.1409';
|
|
60529
|
+
VersionInfo.date = '2025-05-14T02:06:32.990Z';
|
|
60530
|
+
VersionInfo.commit = 'f91fed13b0a0946b3fa9306b480ddf8044b948e2';
|
|
60316
60531
|
|
|
60317
60532
|
/**
|
|
60318
60533
|
* A factory for custom layout engines.
|