Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

45 changes: 29 additions & 16 deletions packages/alphatab/src/AlphaTabApiBase.ts
Original file line number Diff line number Diff line change
Expand Up @@ -352,14 +352,16 @@ export class AlphaTabApiBase<TSettings> {
this.container = uiFacade.rootContainer;

this.activeBeatsChanged = new EventEmitterOfT<ActiveBeatsChangedEventArgs>(() => {
if (this._player.state === PlayerState.Playing && this._currentBeat) {
return new ActiveBeatsChangedEventArgs(this._currentBeat!.beatLookup.highlightedBeats.map(h => h.beat));
const currentBeat = this._currentBeat;
if (this._player.state === PlayerState.Playing && currentBeat) {
return new ActiveBeatsChangedEventArgs(currentBeat.beatLookup.highlightedBeats.map(h => h.beat));
}
return null;
});
this.playedBeatChanged = new EventEmitterOfT<Beat>(() => {
if (this._player.state === PlayerState.Playing && this._currentBeat) {
return this._currentBeat.beat;
const currentBeat = this._currentBeat;
if (this._player.state === PlayerState.Playing && currentBeat) {
return currentBeat.beat;
}
return null;
});
Expand Down Expand Up @@ -395,7 +397,7 @@ export class AlphaTabApiBase<TSettings> {
}

this.container.resize.on(
Environment.throttle(() => {
this.uiFacade.throttle(() => {
if (this._isDestroyed) {
return;
}
Expand Down Expand Up @@ -2192,8 +2194,9 @@ export class AlphaTabApiBase<TSettings> {

this._isInitialBeatCursorUpdate = true;
}
if (this._currentBeat !== null) {
this._cursorUpdateBeat(this._currentBeat!, false, this._previousTick > 10, 1, true);
const currentBeat = this._currentBeat;
if (currentBeat) {
this._cursorUpdateBeat(currentBeat, false, this._previousTick > 10, 1, true);
}
}

Expand Down Expand Up @@ -2351,7 +2354,15 @@ export class AlphaTabApiBase<TSettings> {
this._previousStateForCursor = this._player.state;

this.uiFacade.beginInvoke(() => {
this._internalCursorUpdateBeat(lookupResult, stop, cache!, beatBoundings!, shouldScroll, cursorSpeed);
this._internalCursorUpdateBeat(
lookupResult,
stop,
cache!,
beatBoundings!,
shouldScroll,
cursorSpeed,
forceUpdate
);
});
}

Expand All @@ -2376,7 +2387,8 @@ export class AlphaTabApiBase<TSettings> {
boundsLookup: BoundsLookup,
beatBoundings: BeatBounds,
shouldScroll: boolean,
cursorSpeed: number
cursorSpeed: number,
forceUpdate: boolean
) {
const beat = lookupResult.beat;
const nextBeat = lookupResult.nextBeat?.beat;
Expand Down Expand Up @@ -2418,9 +2430,12 @@ export class AlphaTabApiBase<TSettings> {
let startBeatX = beatBoundings.onNotesX;
if (beatCursor) {
const animationWidth = nextBeatX - beatBoundings.onNotesX;
const relativePosition = this._previousTick - this._currentBeat!.start;
const ratioPosition =
this._currentBeat!.tickDuration > 0 ? relativePosition / this._currentBeat!.tickDuration : 0;
const relativePosition = this._previousTick - lookupResult!.start;
let ratioPosition = lookupResult.tickDuration > 0 ? relativePosition / lookupResult.tickDuration : 0;
// state got out-of-sync
if (ratioPosition > 1) {
ratioPosition = 1;
}
startBeatX = beatBoundings.onNotesX + animationWidth * ratioPosition;
duration -= duration * ratioPosition;

Expand All @@ -2431,6 +2446,7 @@ export class AlphaTabApiBase<TSettings> {
// we do not "reset" the cursor if we are smoothly moving from left to right.
const jumpCursor =
!previousBeatBounds ||
forceUpdate ||
this._isInitialBeatCursorUpdate ||
barBounds.y !== previousBeatBounds.barBounds.masterBarBounds.visualBounds.y ||
startBeatX < previousBeatBounds.onNotesX ||
Expand Down Expand Up @@ -4024,12 +4040,9 @@ export class AlphaTabApiBase<TSettings> {
return;
}

const currentTick = e.currentTick;

this._previousTick = currentTick;
this.uiFacade.beginInvoke(() => {
const cursorSpeed = e.modifiedTempo / e.originalTempo;
this._cursorUpdateTick(currentTick, false, cursorSpeed, false, e.isSeek);
this._cursorUpdateTick(e.currentTick, false, cursorSpeed, false, e.isSeek);
});

this.uiFacade.triggerEvent(this.container, 'playerPositionChanged', e);
Expand Down
54 changes: 21 additions & 33 deletions packages/alphatab/src/Environment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,17 @@ import { GolpeType } from '@coderline/alphatab/model/GolpeType';
import { HarmonicType } from '@coderline/alphatab/model/HarmonicType';
import type { ICanvas } from '@coderline/alphatab/platform/ICanvas';
import { AlphaSynthWebWorklet } from '@coderline/alphatab/platform/javascript/AlphaSynthAudioWorkletOutput';
import { AlphaSynthWebWorker } from '@coderline/alphatab/platform/javascript/AlphaSynthWebWorker';
import { AlphaTabWebWorker } from '@coderline/alphatab/platform/javascript/AlphaTabWebWorker';
import { BrowserUiFacade } from '@coderline/alphatab/platform/javascript/BrowserUiFacade';
import { Html5Canvas } from '@coderline/alphatab/platform/javascript/Html5Canvas';
import { JQueryAlphaTab } from '@coderline/alphatab/platform/javascript/JQueryAlphaTab';
import { WebPlatform } from '@coderline/alphatab/platform/javascript/WebPlatform';
import { SkiaCanvas } from '@coderline/alphatab/platform/skia/SkiaCanvas';
import { CssFontSvgCanvas } from '@coderline/alphatab/platform/svg/CssFontSvgCanvas';
import { AlphaSynthWebWorker } from '@coderline/alphatab/platform/worker/AlphaSynthWebWorker';
import { AlphaTabWebWorker } from '@coderline/alphatab/platform/worker/AlphaTabWebWorker';
import type {
IAlphaTabWorkerGlobalScope
} from '@coderline/alphatab/platform/worker/AlphaTabWorkerProtocol';
import { EffectBandMode, type BarRendererFactory } from '@coderline/alphatab/rendering/BarRendererFactory';
import { AlternateEndingsEffectInfo } from '@coderline/alphatab/rendering/effects/AlternateEndingsEffectInfo';
import { BeatBarreEffectInfo } from '@coderline/alphatab/rendering/effects/BeatBarreEffectInfo';
Expand Down Expand Up @@ -167,6 +171,15 @@ export class Environment {
return Environment._globalThis;
}

/**
* @target web
* @internal
* @partial
*/
public static getGlobalWorkerScope<T>(): IAlphaTabWorkerGlobalScope<T> {
return Environment.globalThis;
}

/**
* @target web
*/
Expand Down Expand Up @@ -206,30 +219,6 @@ export class Environment {
return 'AudioWorkletGlobalScope' in Environment.globalThis;
}

/**
* @target web
* @internal
*/
public static createWebWorker: (settings: Settings) => Worker;

/**
* @target web
* @internal
*/
public static createAudioWorklet: (context: AudioContext, settings: Settings) => Promise<void>;

/**
* @target web
* @partial
*/
public static throttle(action: () => void, delay: number): () => void {
let timeoutId: number = 0;
return () => {
Environment.globalThis.clearTimeout(timeoutId);
timeoutId = Environment.globalThis.setTimeout(action, delay);
};
}

/**
* @target web
*/
Expand Down Expand Up @@ -422,7 +411,7 @@ export class Environment {

renderEngines.set(
'skia',
new RenderEngineFactory(false, () => {
new RenderEngineFactory(true, () => {
return new SkiaCanvas();
})
);
Expand Down Expand Up @@ -637,7 +626,7 @@ export class Environment {
* @target web
*/
public static initializeMain(
createWebWorker: (settings: Settings) => Worker,
createWebWorker: (settings: Settings, nameHint: string) => Worker,
createAudioWorklet: (context: AudioContext, settings: Settings) => Promise<void>
) {
if (Environment.isRunningInWorker || Environment.isRunningInAudioWorklet) {
Expand All @@ -650,8 +639,9 @@ export class Environment {
Environment.highDpiFactor = window.devicePixelRatio;
}

Environment.createWebWorker = createWebWorker;
Environment.createAudioWorklet = createAudioWorklet;
BrowserUiFacade.createAlphaTabWebWorker = s => createWebWorker(s, 'alphaTab Renderer');
BrowserUiFacade.createAlphaSynthWebWorker = s => createWebWorker(s, 'alphaSynth Worker');
BrowserUiFacade.createAlphaSynthAudioWorklet = createAudioWorklet;
}

/**
Expand Down Expand Up @@ -682,9 +672,6 @@ export class Environment {
}
AlphaTabWebWorker.init();
AlphaSynthWebWorker.init();
Environment.createWebWorker = _ => {
throw new AlphaTabError(AlphaTabErrorType.General, 'Nested workers are not supported');
};
}

/**
Expand Down Expand Up @@ -828,6 +815,7 @@ export class Environment {
* create proxy objects for all objects used. This code handles the necessary unwrapping.
* @internal
* @target web
* @partial
*/
public static prepareForPostMessage<T>(object: T): T {
if (!object) {
Expand Down
2 changes: 1 addition & 1 deletion packages/alphatab/src/model/JsonConverter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ export class JsonConverter {
* @param score The score object to serialize
* @returns A serialized score object without ciruclar dependencies that can be used for further serializations.
*/
public static scoreToJsObject(score: Score): unknown {
public static scoreToJsObject(score: Score): Map<string, unknown>|null {
return ScoreSerializer.toJson(score);
}

Expand Down
17 changes: 15 additions & 2 deletions packages/alphatab/src/platform/IUiFacade.ts
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,19 @@ export interface IUiFacade<TSettings> {
*/
beginInvoke(action: () => void): void;

/**
* Creates a throttled/debounced version of the provided action.
* @param action The action to call.
* @param delay The delay to wait for additional call before actually executing.
* @returns A function which executes the provided action after the given delay.
* If multiple calls are made before the action is started, the already scheduled
* action is cancelled and a new one is scheduled after the given delay.
* If called endlessly, the action is never executed.
*
* Already executing actions will not be cancelled but will complete before another action executes.
*/
throttle(action: () => void, delay: number): () => void;

/**
* Tells the UI layer to remove all highlights from highlighted music notation elements.
*/
Expand Down Expand Up @@ -176,7 +189,7 @@ export interface IUiFacade<TSettings> {
scrollToX(scrollElement: IContainer, offset: number, speed: number): void;

/**
* Stops any ongoing scrolling of the given element.
* Stops any ongoing scrolling of the given element.
* @param scrollElement The element which might be scrolling dynamically.
*/
stopScrolling(scrollElement: IContainer): void;
Expand Down Expand Up @@ -208,7 +221,7 @@ export interface IUiFacade<TSettings> {
* Without these overflows we might not have enough scroll space
* and we cannot reach a "sticky cursor" behavior.
*/
setCanvasOverflow(canvasElement:IContainer, overflow: number, isVertical: boolean): void;
setCanvasOverflow(canvasElement: IContainer, overflow: number, isVertical: boolean): void;

/**
* This events is fired when the {@link canRender} property changes.
Expand Down
Loading
Loading