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
15 changes: 15 additions & 0 deletions playground-template/control-template.html
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,21 @@
</div>

<div class="at-player-right">
<div class="btn-group dropup at-output-device">
<button
type="button"
class="btn dropdown-toggle"
data-bs-toggle="dropdown"
aria-haspopup="true"
aria-expanded="false"
title="Output Device: Default"
>
<i class="fas fa-headphones"></i>
</button>
<div class="dropdown-menu dropdown-menu-right">
<a class="dropdown-item" href="#">Default</a>
</div>
</div>
<a
href="#"
class="at-count-in disabled"
Expand Down
57 changes: 41 additions & 16 deletions playground-template/control.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -23,22 +23,22 @@ const defaultSettings = {
};

function applyFonts(settings) {
settings.display.resources.copyrightFont.families = ["Noto Sans"];
settings.display.resources.titleFont.families = ["Noto Serif"];
settings.display.resources.subTitleFont.families = ["Noto Serif"];
settings.display.resources.wordsFont.families = ["Noto Serif"];
settings.display.resources.effectFont.families = ["Noto Serif"];
settings.display.resources.timerFont.families = ["Noto Serif"];
settings.display.resources.fretboardNumberFont.families = ["Noto Sans"];
settings.display.resources.tablatureFont.families = ["Noto Sans"];
settings.display.resources.graceFont.families = ["Noto Sans"];
settings.display.resources.barNumberFont.families = ["Noto Sans"];
settings.display.resources.fingeringFont.families = ["Noto Serif"];
settings.display.resources.inlineFingeringFont.families = ["Noto Serif"];
settings.display.resources.markerFont.families = ["Noto Serif"];
settings.display.resources.directionsFont.families = ["Noto Serif"];
settings.display.resources.numberedNotationFont.families = ["Noto Sans"];
settings.display.resources.numberedNotationGraceFont.families = ["Noto Sans"];
settings.display.resources.copyrightFont.families = ['Noto Sans'];
settings.display.resources.titleFont.families = ['Noto Serif'];
settings.display.resources.subTitleFont.families = ['Noto Serif'];
settings.display.resources.wordsFont.families = ['Noto Serif'];
settings.display.resources.effectFont.families = ['Noto Serif'];
settings.display.resources.timerFont.families = ['Noto Serif'];
settings.display.resources.fretboardNumberFont.families = ['Noto Sans'];
settings.display.resources.tablatureFont.families = ['Noto Sans'];
settings.display.resources.graceFont.families = ['Noto Sans'];
settings.display.resources.barNumberFont.families = ['Noto Sans'];
settings.display.resources.fingeringFont.families = ['Noto Serif'];
settings.display.resources.inlineFingeringFont.families = ['Noto Serif'];
settings.display.resources.markerFont.families = ['Noto Serif'];
settings.display.resources.directionsFont.families = ['Noto Serif'];
settings.display.resources.numberedNotationFont.families = ['Noto Sans'];
settings.display.resources.numberedNotationGraceFont.families = ['Noto Sans'];
}

function createTrackItem(track, trackSelection) {
Expand Down Expand Up @@ -262,6 +262,31 @@ export function setupControl(selector, customSettings) {
}
};

function createOutputDeviceItem(device) {
const item = document.createElement('a');
item.classList.add('dropdown-item');
item.href = '#';
item.onclick = async () => {
await at.setOutputDevice(device);
};
item.innerText = device.label + (device.isDefault ? ' (default)' : '');
return item;
}

control.querySelector('.at-output-device').addEventListener('show.bs.dropdown', async () => {
const devices = await at.enumerateOutputDevices();
if (devices.length === 0) {
return;
}

const list = control.querySelector('.at-output-device .dropdown-menu');
list.innerHTML = '';
for (const d of devices) {
const item = createOutputDeviceItem(d);
list.appendChild(item);
}
});

control.querySelectorAll('.at-speed-options a').forEach(function (a) {
a.onclick = function (e) {
e.preventDefault();
Expand Down
5 changes: 3 additions & 2 deletions src.compiler/csharp/CSharpAstTransformer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import * as ts from 'typescript';
import * as cs from './CSharpAst';
import * as path from 'path';
import CSharpEmitterContext from './CSharpEmitterContext';
import exp from 'constants';

export default class CSharpAstTransformer {
protected _typeScriptFile: ts.SourceFile;
Expand Down Expand Up @@ -1888,7 +1887,7 @@ export default class CSharpAstTransformer {
protected visitMethodSignature(
parent: cs.ClassDeclaration | cs.InterfaceDeclaration,
classElement: ts.MethodSignature
) {
): cs.MethodDeclaration {
const signature = this._context.typeChecker.getSignatureFromDeclaration(classElement);
const returnType = this._context.typeChecker.getReturnTypeOfSignature(signature!);

Expand Down Expand Up @@ -1939,6 +1938,8 @@ export default class CSharpAstTransformer {
}

this._context.registerSymbol(csMethod);

return csMethod;
}
protected mapVisibility(node: ts.Node, fallback: cs.Visibility): cs.Visibility {
if (this._context.isInternal(node)) {
Expand Down
23 changes: 18 additions & 5 deletions src.compiler/csharp/CSharpEmitterContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -649,13 +649,21 @@ export default class CSharpEmitterContext {
if (isEmitted && t.symbol.name !== 'PromiseLike') {
this.addCsNodeDiagnostics(
parent,
'Union type covering multiple types detected, fallback to dynamic',
'Union type covering multiple types detected, fallback to object',
ts.DiagnosticCategory.Warning
);
}
fallbackToObject = true;
} else {
actualType = t;
} else if (actualType !== t) {
if (t.symbol?.name === 'PromiseLike') {
this.addCsNodeDiagnostics(
parent,
'Union type with promise detected, ignoring',
ts.DiagnosticCategory.Warning
);
} else {
actualType = t;
}
}
}

Expand Down Expand Up @@ -954,6 +962,11 @@ export default class CSharpEmitterContext {
}
}

public resolveSymbol(symbol: ts.Symbol): (cs.NamedElement & cs.Node) | undefined {
const symbolKey = this.getSymbolKey(symbol);
return this._symbolLookup.get(symbolKey);
}

public isConst(declaration: cs.FieldDeclaration) {
const symbolKey = this.getSymbolKey(declaration.tsSymbol!);
return this._symbolConst.has(symbolKey);
Expand All @@ -976,8 +989,8 @@ export default class CSharpEmitterContext {
const declaration = symbol.valueDeclaration
? symbol.valueDeclaration
: symbol.declarations && symbol.declarations.length > 0
? symbol.declarations[0]
: undefined;
? symbol.declarations[0]
: undefined;

if (declaration) {
return symbol.name + '_' + declaration.getSourceFile().fileName + '_' + declaration.pos;
Expand Down
99 changes: 63 additions & 36 deletions src.compiler/kotlin/KotlinAstTransformer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,23 @@ export default class KotlinAstTransformer extends CSharpAstTransformer {
return '.kt';
}

public override get targetTag(): string {
return 'kotlin';
}

private _paramReferences: Map<string, cs.Identifier[]>[] = [];
private _paramsWithAssignment: Set<string>[] = [];

private getMethodLocalParameterName(name: string) {
return 'param' + name;
}

protected override visitMethodSignature(parent: cs.ClassDeclaration | cs.InterfaceDeclaration, classElement: ts.MethodSignature) {
const csMethod = super.visitMethodSignature(parent, classElement);

if(!!ts.getJSDocTags(classElement).find(t => t.tagName.text === 'async')) {
csMethod.isAsync = true;
}

return csMethod;
}

protected override buildFileName(fileName: string, context: CSharpEmitterContext): string {
let parts = this.removeExtension(fileName).split(path.sep);
if (parts.length > 0) {
Expand Down Expand Up @@ -68,9 +74,10 @@ export default class KotlinAstTransformer extends CSharpAstTransformer {
protected override visitPrefixUnaryExpression(parent: cs.Node, expression: ts.PrefixUnaryExpression) {
const pre = super.visitPrefixUnaryExpression(parent, expression);

const preUnwrapped = pre && cs.isCastExpression(pre)
? (pre.expression as cs.PrefixUnaryExpression)
: (pre as cs.PrefixUnaryExpression);
const preUnwrapped =
pre && cs.isCastExpression(pre)
? (pre.expression as cs.PrefixUnaryExpression)
: (pre as cs.PrefixUnaryExpression);

if (preUnwrapped) {
switch (preUnwrapped.operator) {
Expand Down Expand Up @@ -229,44 +236,66 @@ export default class KotlinAstTransformer extends CSharpAstTransformer {
// and await expressions are normal method calls.
// this is a problem when we want to use the raw Promise like asyncFunction().then().catch()
// The following code wraps the code to a "alphaTab.core.TypeHelper.suspendToDeferred({ asyncFunction() }).then().catch()

// similarly in reverse cases, when we have suspend function calling a method which returns a Deferred directly (e.g. on async interface methods)
// then we call .await()
if (invocation && cs.isInvocationExpression(invocation)) {
const returnType = this._context.typeChecker.getTypeAtLocation(expression);
const method = this._context.typeChecker.getSymbolAtLocation(expression.expression);

if (returnType?.symbol?.name === "Promise"
&& (method as any)?.parent?.name !== 'Promise'
&& !ts.isAwaitExpression(expression.parent)) {
const suspendToDeferred = {
nodeType: cs.SyntaxKind.InvocationExpression,
} as cs.InvocationExpression;

suspendToDeferred.expression = this.makeMemberAccess(
suspendToDeferred,
this._context.makeTypeName('alphaTab.core.TypeHelper'),
this._context.toMethodName('suspendToDeferred')
if (returnType?.symbol?.name === 'Promise' && (method as any)?.parent?.name !== 'Promise') {
const isSuspend = method?.valueDeclaration && (
(method.valueDeclaration as ts.MethodDeclaration).modifiers?.some(m => m.kind === ts.SyntaxKind.AsyncKeyword) ||
ts.getJSDocTags(method.valueDeclaration!).find(t => t.tagName.text === 'async')
);

suspendToDeferred.arguments = [
{
nodeType: cs.SyntaxKind.LambdaExpression,
parameters: [] as cs.ParameterDeclaration[],
body: invocation,
parent: suspendToDeferred,
returnType: {
nodeType: cs.SyntaxKind.PrimitiveTypeNode,
type: cs.PrimitiveType.Void
} as cs.PrimitiveTypeNode
} as cs.LambdaExpression
];

return suspendToDeferred;
if (!ts.isAwaitExpression(expression.parent) && isSuspend) {
const suspendToDeferred = {
nodeType: cs.SyntaxKind.InvocationExpression
} as cs.InvocationExpression;

suspendToDeferred.expression = this.makeMemberAccess(
suspendToDeferred,
this._context.makeTypeName('alphaTab.core.TypeHelper'),
this._context.toMethodName('suspendToDeferred')
);

suspendToDeferred.arguments = [
{
nodeType: cs.SyntaxKind.LambdaExpression,
parameters: [] as cs.ParameterDeclaration[],
body: invocation,
parent: suspendToDeferred,
returnType: {
nodeType: cs.SyntaxKind.PrimitiveTypeNode,
type: cs.PrimitiveType.Void
} as cs.PrimitiveTypeNode
} as cs.LambdaExpression
];

return suspendToDeferred;
} else if (ts.isAwaitExpression(expression.parent) && !isSuspend) {
const deferredToSuspend = {
nodeType: cs.SyntaxKind.InvocationExpression
} as cs.InvocationExpression;

deferredToSuspend.expression = {
expression: invocation,
member: 'await',
parent: parent,
nodeType: cs.SyntaxKind.MemberAccessExpression
} as cs.MemberAccessExpression;

deferredToSuspend.arguments = [];

return deferredToSuspend;
}
}
}

return invocation;
}


protected override visitConstructorDeclaration(
parent: cs.ClassDeclaration,
classElement: ts.ConstructorDeclaration
Expand Down Expand Up @@ -310,7 +339,6 @@ export default class KotlinAstTransformer extends CSharpAstTransformer {
return func;
}


protected override visitTestClassMethod(parent: cs.ClassDeclaration, d: ts.FunctionDeclaration) {
this._paramReferences.push(new Map<string, cs.Identifier[]>());
this._paramsWithAssignment.push(new Set<string>());
Expand All @@ -327,7 +355,6 @@ export default class KotlinAstTransformer extends CSharpAstTransformer {
return method;
}


protected override visitMethodDeclaration(
parent: cs.ClassDeclaration | cs.InterfaceDeclaration,
classElement: ts.MethodDeclaration
Expand Down Expand Up @@ -559,4 +586,4 @@ export default class KotlinAstTransformer extends CSharpAstTransformer {
}
return null;
}
}
}
2 changes: 1 addition & 1 deletion src.csharp/AlphaTab.Test/AlphaTab.Test.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
<Nullable>enable</Nullable>
<LangVersion>10</LangVersion>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<NoWarn>$(NoWarn);0659;0168</NoWarn>
<NoWarn>$(NoWarn);0659;0168;;1998</NoWarn>
</PropertyGroup>

<ItemGroup>
Expand Down
Loading
Loading