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
2 changes: 1 addition & 1 deletion src.compiler/csharp/CSharpAst.ts
Original file line number Diff line number Diff line change
Expand Up @@ -140,13 +140,13 @@ export interface TypeParameterDeclaration extends NamedElement, Node {
export interface NamedTypeDeclaration extends NamedElement, DocumentedElement, Node, AttributedElement {
typeParameters?: TypeParameterDeclaration[];
visibility: Visibility;
partial: boolean;
}

export interface ClassDeclaration extends NamedTypeDeclaration {
baseClass?: TypeNode;
interfaces?: TypeNode[];
isAbstract: boolean;
partial: boolean;
members: ClassMember[];
}

Expand Down
5 changes: 5 additions & 0 deletions src.compiler/csharp/CSharpAstPrinter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,11 @@ export default class CSharpAstPrinter {
private writeInterfaceDeclaration(d: cs.InterfaceDeclaration) {
this.writeDocumentation(d);
this.writeVisibility(d.visibility);

if (d.partial) {
this.write('partial ');
}

this.write(`interface ${d.name}`);
this.writeTypeParameters(d.typeParameters);

Expand Down
2 changes: 2 additions & 0 deletions src.compiler/csharp/CSharpAstTransformer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -329,6 +329,7 @@ export default class CSharpAstTransformer {
parent: this._csharpFile.namespace,
members: [],
tsNode: node,
partial: false,
skipEmit: this.shouldSkip(node, false),
tsSymbol: this._context.getSymbolForDeclaration(node)
};
Expand Down Expand Up @@ -385,6 +386,7 @@ export default class CSharpAstTransformer {
members: [],
tsNode: node,
skipEmit: this.shouldSkip(node, false),
partial: !!ts.getJSDocTags(node).find(t => t.tagName.text === 'partial'),
tsSymbol: this._context.getSymbolForDeclaration(node)
};

Expand Down
10 changes: 10 additions & 0 deletions src.csharp/AlphaTab.Windows/DelegatedEventEmitter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,16 @@ public DelegatedEventEmitter(Action<Action<T>> on, Action<Action<T>> off)
_off = off;
}

public void On(Action value)
{
// not used internally
}

public void Off(Action value)
{
// not used internally
}

public void On(Action<T> value)
{
_on(value);
Expand Down
41 changes: 41 additions & 0 deletions src.csharp/AlphaTab/EventEmitter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using AlphaTab.Core.EcmaScript;
using AlphaTab.Platform.CSharp;

namespace AlphaTab
{
partial interface IEventEmitterOfT<T>
{
void On(System.Action value);
void Off(System.Action value);
}

partial class EventEmitterOfT<T>
{
private System.Collections.Generic.IDictionary<System.Action, System.Action<T>> _wrappers =
new System.Collections.Generic.Dictionary<System.Action, System.Action<T>>();

[Obsolete("Use event registration overload with parameter.", false)]
public void On(System.Action value)
{
var wrapper = new Action<T>(_=>
{
value();
});
_wrappers[value] = wrapper;
On(wrapper);
}

[Obsolete("Use event unregistration with parameter.", false)]
public void Off(System.Action value)
{
if(_wrappers.TryGetValue(value, out var wrapper))
{
Off(wrapper);
_wrappers.Remove(value);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ public void SetChannelVolume(double channel, double volume)
public IEventEmitter Finished { get; } = new EventEmitter();
public IEventEmitter SoundFontLoaded { get; } = new EventEmitter();
public IEventEmitterOfT<Error> SoundFontLoadFailed { get; } =new EventEmitterOfT<Error>();
public IEventEmitter MidiLoaded { get; } = new EventEmitter();
public IEventEmitterOfT<PositionChangedEventArgs> MidiLoaded { get; } = new EventEmitterOfT<PositionChangedEventArgs>();
public IEventEmitterOfT<Error> MidiLoadFailed { get; } = new EventEmitterOfT<Error>();
public IEventEmitterOfT<PlayerStateChangedEventArgs> StateChanged { get; } = new EventEmitterOfT<PlayerStateChangedEventArgs>();
public IEventEmitterOfT<PositionChangedEventArgs> PositionChanged { get; } = new EventEmitterOfT<PositionChangedEventArgs>();
Expand Down Expand Up @@ -202,9 +202,9 @@ protected virtual void OnSoundFontLoadFailed(Error e)
DispatchOnUiThread(() => ((EventEmitterOfT<Error>)SoundFontLoadFailed).Trigger(e));
}

protected virtual void OnMidiLoaded()
protected virtual void OnMidiLoaded(PositionChangedEventArgs args)
{
DispatchOnUiThread(() => ((EventEmitter)MidiLoaded).Trigger());
DispatchOnUiThread(() => ((EventEmitterOfT<PositionChangedEventArgs>)MidiLoaded).Trigger(args));
}

protected virtual void OnMidiLoadFailed(Error e)
Expand Down
8 changes: 4 additions & 4 deletions src/AlphaTabApiBase.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1221,10 +1221,10 @@ export class AlphaTabApiBase<TSettings> {
this.uiFacade.triggerEvent(this.container, 'soundFontLoaded', null);
}

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

public playerStateChanged: IEventEmitterOfT<PlayerStateChangedEventArgs> = new EventEmitterOfT<
Expand Down
7 changes: 7 additions & 0 deletions src/EventEmitter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@ export interface IEventEmitter {
on(value: () => void): void;
off(value: () => void): void;
}

/**
* @partial
*/
export interface IEventEmitterOfT<T> {
on(value: (arg: T) => void): void;
off(value: (arg: T) => void): void;
Expand All @@ -25,6 +29,9 @@ export class EventEmitter implements IEventEmitter {
}
}

/**
* @partial
*/
export class EventEmitterOfT<T> implements IEventEmitterOfT<T> {
private _listeners: ((arg: T) => void)[] = [];

Expand Down
3 changes: 2 additions & 1 deletion src/platform/javascript/AlphaSynthWebWorker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,8 @@ export class AlphaSynthWebWorker {
currentTime: e.currentTime,
endTime: e.endTime,
currentTick: e.currentTick,
endTick: e.endTick
endTick: e.endTick,
isSeek: e.isSeek
});
}

Expand Down
10 changes: 7 additions & 3 deletions src/platform/javascript/AlphaSynthWebWorkerApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -342,7 +342,7 @@ export class AlphaSynthWebWorkerApi implements IAlphaSynth {
this._timePosition = data.currentTime;
this._tickPosition = data.currentTick;
(this.positionChanged as EventEmitterOfT<PositionChangedEventArgs>).trigger(
new PositionChangedEventArgs(data.currentTime, data.endTime, data.currentTick, data.endTick)
new PositionChangedEventArgs(data.currentTime, data.endTime, data.currentTick, data.endTick, data.isSeek)
);
break;
case 'alphaSynth.playerStateChanged':
Expand All @@ -362,7 +362,9 @@ export class AlphaSynthWebWorkerApi implements IAlphaSynth {
break;
case 'alphaSynth.midiLoaded':
this.checkReadyForPlayback();
(this.midiLoaded as EventEmitter).trigger();
(this.midiLoaded as EventEmitterOfT<PositionChangedEventArgs>).trigger(
new PositionChangedEventArgs(data.currentTime, data.endTime, data.currentTick, data.endTick, data.isSeek)
);
break;
case 'alphaSynth.midiLoadFailed':
this.checkReadyForPlayback();
Expand Down Expand Up @@ -400,7 +402,9 @@ export class AlphaSynthWebWorkerApi implements IAlphaSynth {
readonly finished: IEventEmitter = new EventEmitter();
readonly soundFontLoaded: IEventEmitter = new EventEmitter();
readonly soundFontLoadFailed: IEventEmitterOfT<Error> = new EventEmitterOfT<Error>();
readonly midiLoaded: IEventEmitter = new EventEmitter();
readonly midiLoaded: IEventEmitterOfT<PositionChangedEventArgs> = new EventEmitterOfT<
PositionChangedEventArgs
>();
readonly midiLoadFailed: IEventEmitterOfT<Error> = new EventEmitterOfT<Error>();
readonly stateChanged: IEventEmitterOfT<PlayerStateChangedEventArgs> = new EventEmitterOfT<
PlayerStateChangedEventArgs
Expand Down
17 changes: 9 additions & 8 deletions src/synth/AlphaSynth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ export class AlphaSynth implements IAlphaSynth {
value = SynthHelper.clamp(value, SynthConstants.MinPlaybackSpeed, SynthConstants.MaxPlaybackSpeed);
let oldSpeed: number = this._sequencer.playbackSpeed;
this._sequencer.playbackSpeed = value;
this.updateTimePosition(this._timePosition * (oldSpeed / value));
this.updateTimePosition(this._timePosition * (oldSpeed / value), true);
}

public get tickPosition(): number {
Expand All @@ -108,7 +108,7 @@ export class AlphaSynth implements IAlphaSynth {
this._sequencer.seek(value);

// update the internal position
this.updateTimePosition(value);
this.updateTimePosition(value, true);

// tell the output to reset the already synthesized buffers and request data again
this.output.resetSamples();
Expand Down Expand Up @@ -309,8 +309,9 @@ export class AlphaSynth implements IAlphaSynth {
Logger.debug('AlphaSynth', 'Loading midi from model');
this._sequencer.loadMidi(midiFile);
this._isMidiLoaded = true;
(this.midiLoaded as EventEmitter).trigger();

(this.midiLoaded as EventEmitterOfT<PositionChangedEventArgs>).trigger(
new PositionChangedEventArgs(0, this._sequencer.endTime, 0, this._sequencer.endTick, false)
);
Logger.debug('AlphaSynth', 'Midi successfully loaded');
this.checkReadyForPlayback();
this.tickPosition = 0;
Expand Down Expand Up @@ -339,7 +340,7 @@ export class AlphaSynth implements IAlphaSynth {

private onSamplesPlayed(sampleCount: number): void {
let playedMillis: number = (sampleCount / this._synthesizer.outSampleRate) * 1000;
this.updateTimePosition(this._timePosition + playedMillis);
this.updateTimePosition(this._timePosition + playedMillis, false);
this.checkForFinish();
}

Expand Down Expand Up @@ -376,7 +377,7 @@ export class AlphaSynth implements IAlphaSynth {
}
}

private updateTimePosition(timePosition: number): void {
private updateTimePosition(timePosition: number, isSeek: boolean): void {
// update the real positions
const currentTime: number = (this._timePosition = timePosition);
const currentTick: number = (this._tickPosition = this._sequencer.timePositionToTickPosition(currentTime));
Expand All @@ -389,7 +390,7 @@ export class AlphaSynth implements IAlphaSynth {
`Position changed: (time: ${currentTime}/${endTime}, tick: ${currentTick}/${endTick}, Active Voices: ${this._synthesizer.activeVoiceCount}`
);
(this.positionChanged as EventEmitterOfT<PositionChangedEventArgs>).trigger(
new PositionChangedEventArgs(currentTime, endTime, currentTick, endTick)
new PositionChangedEventArgs(currentTime, endTime, currentTick, endTick, isSeek)
);
}
}
Expand All @@ -399,7 +400,7 @@ export class AlphaSynth implements IAlphaSynth {
readonly finished: IEventEmitter = new EventEmitter();
readonly soundFontLoaded: IEventEmitter = new EventEmitter();
readonly soundFontLoadFailed: IEventEmitterOfT<Error> = new EventEmitterOfT<Error>();
readonly midiLoaded: IEventEmitter = new EventEmitter();
readonly midiLoaded: IEventEmitterOfT<PositionChangedEventArgs> = new EventEmitterOfT<PositionChangedEventArgs>();
readonly midiLoadFailed: IEventEmitterOfT<Error> = new EventEmitterOfT<Error>();
readonly stateChanged: IEventEmitterOfT<PlayerStateChangedEventArgs> = new EventEmitterOfT<
PlayerStateChangedEventArgs
Expand Down
2 changes: 1 addition & 1 deletion src/synth/IAlphaSynth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ export interface IAlphaSynth {
/**
* This event is fired when the Midi file needed for playback was loaded.
*/
readonly midiLoaded: IEventEmitter;
readonly midiLoaded: IEventEmitterOfT<PositionChangedEventArgs>;

/**
* This event is fired when the loading of the Midi file failed.
Expand Down
9 changes: 8 additions & 1 deletion src/synth/PositionChangedEventArgs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@
* Represents the info when the time in the synthesizer changes.
*/
export class PositionChangedEventArgs {
/**
* Gets a value indicating whether the position changed because of time seeking.
*/
public isSeek: boolean;

/**
* Gets the current time in milliseconds.
*/
Expand All @@ -28,11 +33,13 @@ export class PositionChangedEventArgs {
* @param endTime The end time.
* @param currentTick The current tick.
* @param endTick The end tick.
* @param isSeek Whether the time was seeked.
*/
public constructor(currentTime: number, endTime: number, currentTick: number, endTick: number) {
public constructor(currentTime: number, endTime: number, currentTick: number, endTick: number, isSeek:boolean) {
this.currentTime = currentTime;
this.endTime = endTime;
this.currentTick = currentTick;
this.endTick = endTick;
this.isSeek = isSeek;
}
}