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
92 changes: 74 additions & 18 deletions packages/alphatab/src/rendering/BarRendererBase.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import type { BeatGlyphBase } from '@coderline/alphatab/rendering/glyphs/BeatGly
import type { BeatOnNoteGlyphBase } from '@coderline/alphatab/rendering/glyphs/BeatOnNoteGlyphBase';
import type { Glyph } from '@coderline/alphatab/rendering/glyphs/Glyph';
import { LeftToRightLayoutingGlyphGroup } from '@coderline/alphatab/rendering/glyphs/LeftToRightLayoutingGlyphGroup';
import type { ITieGlyph } from '@coderline/alphatab/rendering/glyphs/TieGlyph';
import { ContinuationTieGlyph, type ITieGlyph, type TieGlyph } from '@coderline/alphatab/rendering/glyphs/TieGlyph';
import { VoiceContainerGlyph } from '@coderline/alphatab/rendering/glyphs/VoiceContainerGlyph';
import { InternalSystemsLayoutMode } from '@coderline/alphatab/rendering/layout/ScoreLayout';
import { MultiBarRestBeatContainerGlyph } from '@coderline/alphatab/rendering/MultiBarRestBeatContainerGlyph';
Expand Down Expand Up @@ -94,25 +94,27 @@ export class BarRendererBase {

private _ties: ITieGlyph[] = [];

private _multiSystemSlurs?: ContinuationTieGlyph[];

public topEffects: EffectBandContainer;
public bottomEffects: EffectBandContainer;

public get nextRenderer(): BarRendererBase | null {
if (!this.bar || !this.bar.nextBar) {
return null;
}
return this.scoreRenderer.layout!.getRendererForBar(this.staff.staffId, this.bar.nextBar);
return this.scoreRenderer.layout!.getRendererForBar(this.staff!.staffId, this.bar.nextBar);
}

public get previousRenderer(): BarRendererBase | null {
if (!this.bar || !this.bar.previousBar) {
return null;
}
return this.scoreRenderer.layout!.getRendererForBar(this.staff.staffId, this.bar.previousBar);
return this.scoreRenderer.layout!.getRendererForBar(this.staff!.staffId, this.bar.previousBar);
}

public scoreRenderer: ScoreRenderer;
public staff!: RenderStaff;
public staff?: RenderStaff;
public layoutingInfo!: BarLayoutingInfo;
public bar: Bar;
public additionalMultiRestBars: Bar[] | null = null;
Expand Down Expand Up @@ -239,15 +241,15 @@ export class BarRendererBase {
* scale should be respected.
*/
public get barDisplayScale(): number {
return this.staff.system.staves.length > 1 ? this.bar.masterBar.displayScale : this.bar.displayScale;
return this.staff!.system.staves.length > 1 ? this.bar.masterBar.displayScale : this.bar.displayScale;
}

/**
* Gets the absolute width in which the bar should be displayed in case the model
* scale should be respected.
*/
public get barDisplayWidth(): number {
return this.staff.system.staves.length > 1 ? this.bar.masterBar.displayWidth : this.bar.displayWidth;
return this.staff!.system.staves.length > 1 ? this.bar.masterBar.displayWidth : this.bar.displayWidth;
}

protected wasFirstOfLine: boolean = false;
Expand Down Expand Up @@ -282,6 +284,12 @@ export class BarRendererBase {

private _appliedLayoutingInfo: number = 0;

public afterReverted() {
this.staff = undefined;
this.registerMultiSystemSlurs(undefined);
this.isFinalized = false;
}

public afterStaffBarReverted() {
this.topEffects.afterStaffBarReverted();
this.bottomEffects.afterStaffBarReverted();
Expand Down Expand Up @@ -337,14 +345,30 @@ export class BarRendererBase {

public isFinalized: boolean = false;

public finalizeRenderer(): boolean {
this.isFinalized = true;
public registerMultiSystemSlurs(startedTies: Generator<TieGlyph> | undefined) {
if (!startedTies) {
this._multiSystemSlurs = undefined;
return;
}

let ties: ContinuationTieGlyph[] | undefined = undefined;
for (const g of startedTies) {
const continuation = new ContinuationTieGlyph(g);
continuation.renderer = this;
continuation.tieDirection = g.tieDirection;

if (!ties) {
ties = [];
}
ties.push(continuation);
}

this._multiSystemSlurs = ties;
}

private _finalizeTies(ties: Iterable<ITieGlyph>, barTop: number, barBottom: number): boolean {
let didChangeOverflows = false;
// allow spacing to be used for tie overflows
const barTop = this.y;
const barBottom = this.y + this.height;
for (const t of this._ties) {
for (const t of ties) {
const tie = t as unknown as Glyph;
tie.doLayout();

Expand All @@ -367,6 +391,25 @@ export class BarRendererBase {
}
}
}
return didChangeOverflows;
}

public finalizeRenderer(): boolean {
this.isFinalized = true;

let didChangeOverflows = false;
// allow spacing to be used for tie overflows
const barTop = this.y;
const barBottom = this.y + this.height;

if (this._finalizeTies(this._ties, barTop, barBottom)) {
didChangeOverflows = true;
}

const multiSystemSlurs = this._multiSystemSlurs;
if (multiSystemSlurs && this._finalizeTies(multiSystemSlurs, barTop, barBottom)) {
didChangeOverflows = true;
}

const topHeightChanged = this.topEffects.finalizeEffects();
const bottomHeightChanged = this.bottomEffects.finalizeEffects();
Expand All @@ -383,8 +426,8 @@ export class BarRendererBase {
}

private _registerStaffOverflow() {
this.staff.registerOverflowTop(this.topOverflow);
this.staff.registerOverflowBottom(this.bottomOverflow);
this.staff!.registerOverflowTop(this.topOverflow);
this.staff!.registerOverflowBottom(this.bottomOverflow);
}

public doLayout(): void {
Expand Down Expand Up @@ -500,7 +543,7 @@ export class BarRendererBase {
}

protected updateSizes(): void {
this.staff.registerStaffTop(0);
this.staff!.registerStaffTop(0);
const voiceContainers: Map<number, VoiceContainerGlyph> = this._voiceContainers;
const beatGlyphsStart: number = this.beatGlyphsStart;
let postBeatStart: number = beatGlyphsStart;
Expand All @@ -524,7 +567,7 @@ export class BarRendererBase {
this.height += this.layoutingInfo.height;
this.height = Math.ceil(this.height);

this.staff.registerStaffBottom(this.height);
this.staff!.registerStaffBottom(this.height);
}

protected addPreBeatGlyph(g: Glyph): void {
Expand Down Expand Up @@ -566,10 +609,10 @@ export class BarRendererBase {

this.paintContent(cx, cy, canvas);

const topEffectBandY = cy + this.y - this.staff.topOverflow;
const topEffectBandY = cy + this.y - this.staff!.topOverflow;
this.topEffects.paint(cx + this.x, topEffectBandY, canvas);

const bottomEffectBandY = cy + this.y + this.height + this.staff.bottomOverflow - this.bottomEffects.height;
const bottomEffectBandY = cy + this.y + this.height + this.staff!.bottomOverflow - this.bottomEffects.height;
this.bottomEffects.paint(cx + this.x, bottomEffectBandY, canvas);
}

Expand All @@ -585,6 +628,19 @@ export class BarRendererBase {

canvas.color = this.resources.mainGlyphColor;
this._postBeatGlyphs.paint(cx + this.x, cy + this.y, canvas);

this._paintMultiSystemSlurs(cx, cy, canvas);
}

private _paintMultiSystemSlurs(cx: number, cy: number, canvas: ICanvas) {
const multiSystemSlurs = this._multiSystemSlurs;
if (!multiSystemSlurs) {
return;
}

for (const slur of multiSystemSlurs) {
slur.paint(cx, cy, canvas);
}
}

protected paintBackground(cx: number, cy: number, canvas: ICanvas): void {
Expand Down
2 changes: 1 addition & 1 deletion packages/alphatab/src/rendering/EffectBand.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ export class EffectBand extends Glyph {
public static shouldCreateGlyph(beat: Beat, info: EffectInfo, renderer: BarRendererBase) {
return (
info.shouldCreateGlyph(renderer.settings, beat) &&
(!info.hideOnMultiTrack || renderer.staff.trackIndex === 0)
(!info.hideOnMultiTrack || renderer.staff!.trackIndex === 0)
);
}

Expand Down
7 changes: 5 additions & 2 deletions packages/alphatab/src/rendering/LineBarRenderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { Duration } from '@coderline/alphatab/model/Duration';
import { GraceType } from '@coderline/alphatab/model/GraceType';
import { ModelUtils } from '@coderline/alphatab/model/ModelUtils';
import { MusicFontSymbol } from '@coderline/alphatab/model/MusicFontSymbol';
import type { Note } from '@coderline/alphatab/model/Note';
import type { TupletGroup } from '@coderline/alphatab/model/TupletGroup';
import { NotationMode } from '@coderline/alphatab/NotationSettings';
import { CanvasHelper, type ICanvas, TextAlign, TextBaseline } from '@coderline/alphatab/platform/ICanvas';
Expand Down Expand Up @@ -138,7 +139,7 @@ export abstract class LineBarRenderer extends BarRendererBase {

// during system fitting it can happen that we have fraction widths
// but to have lines until the full end-pixel we round up.
// this way we avoid holes,
// this way we avoid holes,
const lineWidth = this.width;

// we want the lines to be exactly virtually aligned with the respective Y-position
Expand Down Expand Up @@ -1120,8 +1121,10 @@ export abstract class LineBarRenderer extends BarRendererBase {
protected getMinLineOfBeat(_beat: Beat): number {
return 0;
}

protected getMaxLineOfBeat(_beat: Beat): number {
return 0;
}

public abstract getNoteLine(note: Note): number;
}
2 changes: 1 addition & 1 deletion packages/alphatab/src/rendering/NumberedBarRenderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,7 @@ export class NumberedBarRenderer extends LineBarRenderer {
}
}

public getNoteLine() {
public getNoteLine(_note: Note) {
return 0;
}

Expand Down
44 changes: 36 additions & 8 deletions packages/alphatab/src/rendering/NumberedBeatContainerGlyph.ts
Original file line number Diff line number Diff line change
@@ -1,31 +1,41 @@
import type { Note } from '@coderline/alphatab/model/Note';
import { BeatContainerGlyph } from '@coderline/alphatab/rendering/glyphs/BeatContainerGlyph';
import { NumberedTieGlyph } from '@coderline/alphatab/rendering//glyphs/NumberedTieGlyph';
import { BeatContainerGlyph } from '@coderline/alphatab/rendering/glyphs/BeatContainerGlyph';
import { NumberedSlurGlyph } from '@coderline/alphatab/rendering/glyphs/NumberedSlurGlyph';
import type { TieGlyph } from '@coderline/alphatab/rendering/glyphs/TieGlyph';

/**
* @internal
*/
export class NumberedBeatContainerGlyph extends BeatContainerGlyph {
private _slurs: Map<string, TieGlyph> = new Map<string, TieGlyph>();
private _effectSlurs: NumberedSlurGlyph[] = [];

public override doLayout(): void {
this._slurs.clear();
this._effectSlurs = [];
super.doLayout();
}

protected override createTies(n: Note): void {
// create a tie if any effect requires it
if (!n.isVisible) {
return;
}

if (n.isTieOrigin && n.tieDestination!.isVisible) {
const tie = new NumberedTieGlyph(n, n.tieDestination!, false);
if (n.isTieOrigin && n.tieDestination!.isVisible && !this._slurs.has('numbered.tie')) {
const tie = new NumberedTieGlyph(`numbered.tie.${n.beat.id}`, n, n.tieDestination!, false);
this.addTie(tie);
this._slurs.set(tie.slurEffectId, tie);
}
if (n.isTieDestination) {
const tie = new NumberedTieGlyph(n.tieOrigin!, n, true);
const tie = new NumberedTieGlyph(`numbered.tie.${n.tieOrigin!.beat.id}`, n.tieOrigin!, n, true);
this.addTie(tie);
}
if (n.isLeftHandTapped && !n.isHammerPullDestination) {
const tapSlur = new NumberedTieGlyph(n, n, false);
if (n.isLeftHandTapped && !n.isHammerPullDestination && !this._slurs.has(`numbered.tie.leftHandTap.${n.beat.id}`)) {
const tapSlur = new NumberedTieGlyph(`numbered.tie.leftHandTap.${n.beat.id}`, n, n, false);
this.addTie(tapSlur);
this._slurs.set(tapSlur.slurEffectId, tapSlur);
}
// start effect slur on first beat
if (n.isEffectSlurOrigin && n.effectSlurDestination) {
Expand All @@ -36,12 +46,22 @@ export class NumberedBeatContainerGlyph extends BeatContainerGlyph {
break;
}
}

if (!expanded) {
const effectSlur = new NumberedSlurGlyph(n, n.effectSlurDestination, false, false);
const effectSlur = new NumberedSlurGlyph(
`numbered.slur.effect`,
n,
n.effectSlurDestination,
false,
false
);
this._effectSlurs.push(effectSlur);
this.addTie(effectSlur);
this._slurs.set(effectSlur.slurEffectId, effectSlur);
this._slurs.set('numbered.slur.effect', effectSlur);
}
}

// end effect slur on last beat
if (n.isEffectSlurDestination && n.effectSlurOrigin) {
let expanded: boolean = false;
Expand All @@ -52,9 +72,17 @@ export class NumberedBeatContainerGlyph extends BeatContainerGlyph {
}
}
if (!expanded) {
const effectSlur = new NumberedSlurGlyph(n.effectSlurOrigin, n, false, true);
const effectSlur = new NumberedSlurGlyph(
`numbered.slur.effect`,
n.effectSlurOrigin,
n,
false,
true
);
this._effectSlurs.push(effectSlur);
this.addTie(effectSlur);
this._slurs.set(effectSlur.slurEffectId, effectSlur);
this._slurs.set('numbered.slur.effect', effectSlur);
}
}
}
Expand Down
4 changes: 4 additions & 0 deletions packages/alphatab/src/rendering/ScoreBarRenderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -484,6 +484,10 @@ export class ScoreBarRenderer extends LineBarRenderer {
}
}

public override getNoteLine(note: Note): number {
return this.accidentalHelper.getNoteSteps(note) / 2;
}

public getNoteSteps(n: Note): number {
return this.accidentalHelper.getNoteSteps(n);
}
Expand Down
Loading