Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fully destroy alphaTab player #595

Merged
merged 3 commits into from
May 8, 2021
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
6 changes: 6 additions & 0 deletions src.csharp/AlphaTab.Windows/NAudioSynthOutput.cs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,12 @@ public void Open()
((EventEmitter) Ready).Trigger();
}

/// <inheritdoc />
public void Destroy()
{
Dispose();
}

/// <inheritdoc />
public void Dispose()
{
Expand Down
94 changes: 78 additions & 16 deletions src/AlphaTabApiBase.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ class SelectionInfo {
export class AlphaTabApiBase<TSettings> {
private _startTime: number = 0;
private _trackIndexes: number[] | null = null;
private _isDestroyed: boolean = false;
/**
* Gets the UI facade to use for interacting with the user interface.
*/
Expand Down Expand Up @@ -122,6 +123,9 @@ export class AlphaTabApiBase<TSettings> {

this.container.resize.on(
Environment.throttle(() => {
if (this._isDestroyed) {
return;
}
if (this.container.width !== this.renderer.width) {
this.triggerResize();
}
Expand Down Expand Up @@ -164,6 +168,7 @@ export class AlphaTabApiBase<TSettings> {
* Destroys the alphaTab control and restores the initial state of the UI.
*/
public destroy(): void {
this._isDestroyed = true;
if (this.player) {
this.player.destroy();
}
Expand Down Expand Up @@ -678,7 +683,11 @@ export class AlphaTabApiBase<TSettings> {
// we generate a new midi file containing only the beat
let midiFile: MidiFile = new MidiFile();
let handler: AlphaSynthMidiFileHandler = new AlphaSynthMidiFileHandler(midiFile);
let generator: MidiFileGenerator = new MidiFileGenerator(beat.voice.bar.staff.track.score, this.settings, handler);
let generator: MidiFileGenerator = new MidiFileGenerator(
beat.voice.bar.staff.track.score,
this.settings,
handler
);
generator.generateSingleBeat(beat);

this.player.playOneTimeMidiFile(midiFile);
Expand All @@ -696,13 +705,16 @@ export class AlphaTabApiBase<TSettings> {
// we generate a new midi file containing only the beat
let midiFile: MidiFile = new MidiFile();
let handler: AlphaSynthMidiFileHandler = new AlphaSynthMidiFileHandler(midiFile);
let generator: MidiFileGenerator = new MidiFileGenerator(note.beat.voice.bar.staff.track.score, this.settings, handler);
let generator: MidiFileGenerator = new MidiFileGenerator(
note.beat.voice.bar.staff.track.score,
this.settings,
handler
);
generator.generateSingleNote(note);

this.player.playOneTimeMidiFile(midiFile);
}


private _cursorWrapper: IContainer | null = null;
private _barCursor: IContainer | null = null;
private _beatCursor: IContainer | null = null;
Expand Down Expand Up @@ -867,7 +879,7 @@ export class AlphaTabApiBase<TSettings> {
if (
nextBeatBoundings &&
nextBeatBoundings.barBounds.masterBarBounds.staveGroupBounds ===
barBoundings.staveGroupBounds
barBoundings.staveGroupBounds
) {
nextBeatX = nextBeatBoundings.visualBounds.x;
}
Expand Down Expand Up @@ -943,6 +955,9 @@ export class AlphaTabApiBase<TSettings> {

public playedBeatChanged: IEventEmitterOfT<Beat> = new EventEmitterOfT<Beat>();
private onPlayedBeatChanged(beat: Beat): void {
if (this._isDestroyed) {
return;
}
(this.playedBeatChanged as EventEmitterOfT<Beat>).trigger(beat);
this.uiFacade.triggerEvent(this.container, 'playedBeatChanged', beat);
}
Expand All @@ -956,6 +971,10 @@ export class AlphaTabApiBase<TSettings> {
public beatMouseUp: IEventEmitterOfT<Beat | null> = new EventEmitterOfT<Beat | null>();

private onBeatMouseDown(originalEvent: IMouseEventArgs, beat: Beat): void {
if (this._isDestroyed) {
return;
}

if (
this.settings.player.enablePlayer &&
this.settings.player.enableCursor &&
Expand All @@ -970,6 +989,10 @@ export class AlphaTabApiBase<TSettings> {
}

private onBeatMouseMove(originalEvent: IMouseEventArgs, beat: Beat): void {
if (this._isDestroyed) {
return;
}

if (this.settings.player.enableUserInteraction) {
if (!this._selectionEnd || this._selectionEnd.beat !== beat) {
this._selectionEnd = new SelectionInfo(beat);
Expand All @@ -981,6 +1004,10 @@ export class AlphaTabApiBase<TSettings> {
}

private onBeatMouseUp(originalEvent: IMouseEventArgs, beat: Beat | null): void {
if (this._isDestroyed) {
return;
}

if (this.settings.player.enableUserInteraction) {
// for the selection ensure start < end
if (this._selectionEnd) {
Expand Down Expand Up @@ -1046,7 +1073,6 @@ export class AlphaTabApiBase<TSettings> {
} else {
this.cursorSelectRange(null, null);
}

}

private setupClickHandling(): void {
Expand Down Expand Up @@ -1183,91 +1209,127 @@ export class AlphaTabApiBase<TSettings> {

public scoreLoaded: IEventEmitterOfT<Score> = new EventEmitterOfT<Score>();
private onScoreLoaded(score: Score): void {
if (this._isDestroyed) {
return;
}
(this.scoreLoaded as EventEmitterOfT<Score>).trigger(score);
this.uiFacade.triggerEvent(this.container, 'scoreLoaded', score);
}

public resize: IEventEmitterOfT<ResizeEventArgs> = new EventEmitterOfT<ResizeEventArgs>();
private onResize(e: ResizeEventArgs): void {
if (this._isDestroyed) {
return;
}
(this.resize as EventEmitterOfT<ResizeEventArgs>).trigger(e);
this.uiFacade.triggerEvent(this.container, 'resize', e);
}

public renderStarted: IEventEmitterOfT<boolean> = new EventEmitterOfT<boolean>();
private onRenderStarted(resize: boolean): void {
if (this._isDestroyed) {
return;
}
(this.renderStarted as EventEmitterOfT<boolean>).trigger(resize);
this.uiFacade.triggerEvent(this.container, 'renderStarted', resize);
}

public renderFinished: IEventEmitterOfT<RenderFinishedEventArgs> = new EventEmitterOfT<RenderFinishedEventArgs>();
private onRenderFinished(renderingResult: RenderFinishedEventArgs): void {
if (this._isDestroyed) {
return;
}
(this.renderFinished as EventEmitterOfT<RenderFinishedEventArgs>).trigger(renderingResult);
this.uiFacade.triggerEvent(this.container, 'renderFinished', renderingResult);
}

public postRenderFinished: IEventEmitter = new EventEmitter();
private onPostRenderFinished(): void {
if (this._isDestroyed) {
return;
}
(this.postRenderFinished as EventEmitter).trigger();
this.uiFacade.triggerEvent(this.container, 'postRenderFinished', null);
}

public error: IEventEmitterOfT<Error> = new EventEmitterOfT<Error>();
public onError(error: Error): void {
if (this._isDestroyed) {
return;
}
Logger.error('API', 'An unexpected error occurred', error);
(this.error as EventEmitterOfT<Error>).trigger(error);
this.uiFacade.triggerEvent(this.container, 'error', error);
}

public playerReady: IEventEmitter = new EventEmitter();
private onPlayerReady(): void {
if (this._isDestroyed) {
return;
}
(this.playerReady as EventEmitter).trigger();
this.uiFacade.triggerEvent(this.container, 'playerReady', null);
}

public playerFinished: IEventEmitter = new EventEmitter();
private onPlayerFinished(): void {
if (this._isDestroyed) {
return;
}
(this.playerFinished as EventEmitter).trigger();
this.uiFacade.triggerEvent(this.container, 'playerFinished', null);
}

public soundFontLoaded: IEventEmitter = new EventEmitter();
private onSoundFontLoaded(): void {
if (this._isDestroyed) {
return;
}
(this.soundFontLoaded as EventEmitter).trigger();
this.uiFacade.triggerEvent(this.container, 'soundFontLoaded', null);
}

public midiLoad: IEventEmitterOfT<MidiFile> = new EventEmitterOfT<MidiFile>();
private onMidiLoad(e:MidiFile): void {
private onMidiLoad(e: MidiFile): void {
if (this._isDestroyed) {
return;
}
(this.midiLoad as EventEmitterOfT<MidiFile>).trigger(e);
this.uiFacade.triggerEvent(this.container, 'midiLoad', e);
}

public midiLoaded: IEventEmitterOfT<PositionChangedEventArgs> = new EventEmitterOfT<PositionChangedEventArgs>();
private onMidiLoaded(e:PositionChangedEventArgs): void {
private onMidiLoaded(e: PositionChangedEventArgs): void {
if (this._isDestroyed) {
return;
}
(this.midiLoaded as EventEmitterOfT<PositionChangedEventArgs>).trigger(e);
this.uiFacade.triggerEvent(this.container, 'midiFileLoaded', e);
}

public playerStateChanged: IEventEmitterOfT<PlayerStateChangedEventArgs> = new EventEmitterOfT<
PlayerStateChangedEventArgs
>();
public playerStateChanged: IEventEmitterOfT<PlayerStateChangedEventArgs> = new EventEmitterOfT<PlayerStateChangedEventArgs>();
private onPlayerStateChanged(e: PlayerStateChangedEventArgs): void {
if (this._isDestroyed) {
return;
}
(this.playerStateChanged as EventEmitterOfT<PlayerStateChangedEventArgs>).trigger(e);
this.uiFacade.triggerEvent(this.container, 'playerStateChanged', e);
}

public playerPositionChanged: IEventEmitterOfT<PositionChangedEventArgs> = new EventEmitterOfT<
PositionChangedEventArgs
>();
public playerPositionChanged: IEventEmitterOfT<PositionChangedEventArgs> = new EventEmitterOfT<PositionChangedEventArgs>();
private onPlayerPositionChanged(e: PositionChangedEventArgs): void {
if (this._isDestroyed) {
return;
}
(this.playerPositionChanged as EventEmitterOfT<PositionChangedEventArgs>).trigger(e);
this.uiFacade.triggerEvent(this.container, 'playerPositionChanged', e);
}

public midiEventsPlayed: IEventEmitterOfT<MidiEventsPlayedEventArgs> = new EventEmitterOfT<
MidiEventsPlayedEventArgs
>();
public midiEventsPlayed: IEventEmitterOfT<MidiEventsPlayedEventArgs> = new EventEmitterOfT<MidiEventsPlayedEventArgs>();
private onMidiEventsPlayed(e: MidiEventsPlayedEventArgs): void {
if (this._isDestroyed) {
return;
}
(this.midiEventsPlayed as EventEmitterOfT<MidiEventsPlayedEventArgs>).trigger(e);
this.uiFacade.triggerEvent(this.container, 'midiEventsPlayed', e);
}
Expand Down
5 changes: 5 additions & 0 deletions src/platform/javascript/AlphaSynthWebAudioOutput.ts
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,11 @@ export class AlphaSynthWebAudioOutput implements ISynthOutput {
this._audioNode = null;
}

public destroy(): void {
this.pause();
this._context?.close();
}

public addSamples(f: Float32Array): void {
this._circularBuffer.write(f, 0, f.length);
}
Expand Down
6 changes: 6 additions & 0 deletions src/platform/javascript/AlphaSynthWebWorker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,12 @@ export class AlphaSynthWebWorker {
case 'alphaSynth.resetChannelStates':
this._player.resetChannelStates();
break;
case 'alphaSynth.destroy':
this._player.destroy();
this._main.postMessage({
cmd: 'alphaSynth.destroyed'
});
break;
}
}

Expand Down
10 changes: 9 additions & 1 deletion src/platform/javascript/AlphaSynthWebWorkerApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,9 @@ export class AlphaSynthWebWorkerApi implements IAlphaSynth {
}

public destroy(): void {
this._synth.terminate();
this._synth.postMessage({
cmd: 'alphaSynth.destroy'
});
}

//
Expand Down Expand Up @@ -349,6 +351,9 @@ export class AlphaSynthWebWorkerApi implements IAlphaSynth {
this._workerIsReady = true;
this.checkReady();
break;
case 'alphaSynth.destroyed':
this._synth.terminate();
break;
case 'alphaSynth.readyForPlayback':
this._workerIsReadyForPlayback = true;
this.checkReadyForPlayback();
Expand Down Expand Up @@ -399,6 +404,9 @@ export class AlphaSynthWebWorkerApi implements IAlphaSynth {
case 'alphaSynth.output.pause':
this._output.pause();
break;
case 'alphaSynth.output.destroy':
this._output.destroy();
break;
case 'alphaSynth.output.resetSamples':
this._output.resetSamples();
break;
Expand Down
6 changes: 6 additions & 0 deletions src/platform/javascript/AlphaSynthWorkerSynthOutput.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,12 @@ export class AlphaSynthWorkerSynthOutput implements ISynthOutput {
(this.ready as EventEmitter).trigger();
}

public destroy(): void {
this._worker.postMessage({
cmd: 'alphaSynth.output.destroy'
});
}

private handleMessage(e: MessageEvent): void {
let data: any = e.data;
let cmd: any = data.cmd;
Expand Down
1 change: 1 addition & 0 deletions src/synth/AlphaSynth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ export class AlphaSynth implements IAlphaSynth {
public destroy(): void {
Logger.debug('AlphaSynth', 'Destroying player');
this.stop();
this.output.destroy();
}

/**
Expand Down
5 changes: 5 additions & 0 deletions src/synth/ISynthOutput.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@ export interface ISynthOutput {
*/
play(): void;

/**
* Requests the output to destroy itself.
*/
destroy(): void;

/**
* Called when the output should stop the playback.
*/
Expand Down
4 changes: 4 additions & 0 deletions test/audio/TestOutput.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ export class TestOutput implements ISynthOutput {
// nothing to do
}

public destroy(): void {
// nothing to do
}

public next(): void {
(this.sampleRequest as EventEmitter).trigger();
}
Expand Down