Skip to content

Commit

Permalink
Additional cases for new tick lookup (#1334)
Browse files Browse the repository at this point in the history
  • Loading branch information
Danielku15 authored Dec 31, 2023
1 parent a8bb1a7 commit 398064a
Show file tree
Hide file tree
Showing 6 changed files with 300 additions and 105 deletions.
7 changes: 4 additions & 3 deletions src/AlphaTabApiBase.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ import { MidiEventType } from '@src/midi/MidiEvent';
import { MidiEventsPlayedEventArgs } from '@src/synth/MidiEventsPlayedEventArgs';
import { PlaybackRangeChangedEventArgs } from '@src/synth/PlaybackRangeChangedEventArgs';
import { ActiveBeatsChangedEventArgs } from '@src/synth/ActiveBeatsChangedEventArgs';
import { BeatTickLookupItem } from './midi/BeatTickLookup';

class SelectionInfo {
public beat: Beat;
Expand Down Expand Up @@ -983,7 +984,7 @@ export class AlphaTabApiBase<TSettings> {
nextBeat: Beat | null,
duration: number,
stop: boolean,
beatsToHighlight: Beat[],
beatsToHighlight: BeatTickLookupItem[],
cache: BoundsLookup,
beatBoundings: BeatBounds,
shouldScroll: boolean
Expand Down Expand Up @@ -1018,7 +1019,7 @@ export class AlphaTabApiBase<TSettings> {
if (this._playerState === PlayerState.Playing && !stop) {
if (this.settings.player.enableElementHighlighting) {
for (let highlight of beatsToHighlight) {
let className: string = BeatContainerGlyph.getGroupId(highlight);
let className: string = BeatContainerGlyph.getGroupId(highlight.beat);
this.uiFacade.highlightElements(className, beat.voice.bar.index);
}
}
Expand Down Expand Up @@ -1058,7 +1059,7 @@ export class AlphaTabApiBase<TSettings> {
// trigger an event for others to indicate which beat/bar is played
if (shouldNotifyBeatChange) {
this.onPlayedBeatChanged(beat);
this.onActiveBeatsChanged(new ActiveBeatsChangedEventArgs(beatsToHighlight));
this.onActiveBeatsChanged(new ActiveBeatsChangedEventArgs(beatsToHighlight.map(i => i.beat)));
}
}

Expand Down
44 changes: 37 additions & 7 deletions src/midi/BeatTickLookup.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,35 @@
import { Beat } from '@src/model/Beat';

/**
* Represents a beat and when it is actually played according to the generated audio.
*/
export class BeatTickLookupItem {
/**
* Gets the beat represented by this item.
*/
public readonly beat: Beat;

/**
* Gets the playback start of the beat according to the generated audio.
*/
public readonly playbackStart: number;

/**
* Gets the playback start of the beat duration according to the generated audio.
*/
public readonly playbackDuration: number;

public constructor(
beat: Beat,
playbackStart: number,
playbackDuration: number
) {
this.beat = beat;
this.playbackStart = playbackStart;
this.playbackDuration = playbackDuration;
}
}

/**
* Represents the time period, for which one or multiple {@link Beat}s are played
*/
Expand All @@ -21,7 +51,7 @@ export class BeatTickLookup {
* the beat of this lookup starts playing. This might not mean
* the beats start at this position.
*/
public highlightedBeats: Beat[] = [];
public highlightedBeats: BeatTickLookupItem[] = [];

/**
* Gets the next BeatTickLookup which comes after this one and is in the same
Expand All @@ -42,7 +72,7 @@ export class BeatTickLookup {
return this.end - this.start;
}

public constructor(start:number, end:number) {
public constructor(start: number, end: number) {
this.start = start;
this.end = end;
}
Expand All @@ -51,13 +81,13 @@ export class BeatTickLookup {
* Marks the given beat as highlighed as part of this lookup.
* @param beat The beat to add.
*/
public highlightBeat(beat: Beat): void {
if(beat.isEmpty) {
public highlightBeat(beat: Beat, playbackStart: number, playbackDuration: number): void {
if (beat.isEmpty) {
return;
}
if (!this._highlightedBeats.has(beat.id)) {
this._highlightedBeats.set(beat.id, true);
this.highlightedBeats.push(beat);
this.highlightedBeats.push(new BeatTickLookupItem(beat, playbackStart, playbackDuration));
}
}

Expand All @@ -68,8 +98,8 @@ export class BeatTickLookup {
*/
public getVisibleBeatAtStart(visibleTracks: Set<number>): Beat | null {
for (const b of this.highlightedBeats) {
if (b.playbackStart == this.start && visibleTracks.has(b.voice.bar.staff.track.index)) {
return b;
if (b.playbackStart == this.start && visibleTracks.has(b.beat.voice.bar.staff.track.index)) {
return b.beat;
}
}
return null;
Expand Down
50 changes: 28 additions & 22 deletions src/midi/MasterBarTickLookup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,12 @@ export class MasterBarTickLookup {
*/
public nextMasterBar: MasterBarTickLookup | null = null;


/**
* Gets or sets the {@link MasterBarTickLookup} of the previous masterbar in the {@link Score}
*/
public previousMasterBar: MasterBarTickLookup | null = null;

/**
* Adds a new beat to this masterbar following the slicing logic required by the MidiTickLookup.
* @returns The first item of the chain which was affected.
Expand Down Expand Up @@ -203,7 +209,7 @@ export class MasterBarTickLookup {
// Variant A
if (this.firstBeat == null) {
const n1 = new BeatTickLookup(start, end);
n1.highlightBeat(beat);
n1.highlightBeat(beat, start, duration);

this.insertAfter(this.firstBeat, n1);
}
Expand All @@ -212,7 +218,7 @@ export class MasterBarTickLookup {
else if (start >= this.lastBeat!.end) {
// using the end here allows merge of B & C
const n1 = new BeatTickLookup(this.lastBeat!.end, end);
n1.highlightBeat(beat);
n1.highlightBeat(beat, start, duration);

this.insertAfter(this.lastBeat, n1);
}
Expand Down Expand Up @@ -245,41 +251,41 @@ export class MasterBarTickLookup {
if (end == l1.start) {
// using firstBeat.start here allows merge of D & E
const n1 = new BeatTickLookup(start, l1.start);
n1.highlightBeat(beat);
n1.highlightBeat(beat, start, duration);

this.insertBefore(this.firstBeat, n1);
}
// Variant F
else if (end < l1.end) {
const n1 = new BeatTickLookup(start, l1.start);
n1.highlightBeat(beat);
n1.highlightBeat(beat, start, duration);
this.insertBefore(l1, n1);

const n2 = new BeatTickLookup(l1.start, end);
for (const b of l1.highlightedBeats) {
n2.highlightBeat(b);
n2.highlightBeat(b.beat, b.playbackStart, b.playbackDuration);
}
n2.highlightBeat(beat);
n2.highlightBeat(beat, start, duration);
this.insertBefore(l1, n2);

l1.start = end;
}
// Variant G
else if (end == l1.end) {
const n1 = new BeatTickLookup(start, l1.start);
n1.highlightBeat(beat);
n1.highlightBeat(beat, start, duration);

l1.highlightBeat(beat);
l1.highlightBeat(beat, start, duration);

this.insertBefore(l1, n1);
}
// Variant H
else /* end > this.firstBeat.end */ {

const n1 = new BeatTickLookup(start, l1.start);
n1.highlightBeat(beat);
n1.highlightBeat(beat, start, duration);

l1.highlightBeat(beat);
l1.highlightBeat(beat, start, duration);

this.insertBefore(l1, n1);

Expand All @@ -291,11 +297,11 @@ export class MasterBarTickLookup {
if (end == l1.end) {
const n1 = new BeatTickLookup(l1.start, start);
for (const b of l1.highlightedBeats) {
n1.highlightBeat(b);
n1.highlightBeat(b.beat, b.playbackStart, b.playbackDuration);
}

l1.start = start;
l1.highlightBeat(beat);
l1.highlightBeat(beat, start, duration);

this.insertBefore(l1, n1)
}
Expand All @@ -308,48 +314,48 @@ export class MasterBarTickLookup {
this.insertBefore(l1, n2)

for (const b of l1.highlightedBeats) {
n1.highlightBeat(b)
n2.highlightBeat(b)
n1.highlightBeat(b.beat, b.playbackStart, b.playbackDuration)
n2.highlightBeat(b.beat, b.playbackStart, b.playbackDuration)
}
n2.highlightBeat(beat);
n2.highlightBeat(beat, start, duration);

l1.start = end;
}
// Variant K
else /* end > l1.end */ {
const n1 = new BeatTickLookup(l1.start, start);
for (const b of l1.highlightedBeats) {
n1.highlightBeat(b);
n1.highlightBeat(b.beat, b.playbackStart, b.playbackDuration);
}

l1.start = start;
l1.highlightBeat(beat);
l1.highlightBeat(beat, start, duration);

this.insertBefore(l1, n1);

this.addBeat(beat, l1.end, end - l1.end);
}
}
else /* start == l1.start */ {
// Variant L
if (end === l1.end) {
l1.highlightBeat(beat);
l1.highlightBeat(beat, start, end);
}
// Variant M
else if (end < l1.end) {
const n1 = new BeatTickLookup(l1.start, end);
for (const b of l1.highlightedBeats) {
n1.highlightBeat(b);
n1.highlightBeat(b.beat, b.playbackStart, b.playbackDuration);
}
n1.highlightBeat(beat);
n1.highlightBeat(beat, start, duration);

l1.start = end;

this.insertBefore(l1, n1);
}
// variant N
else /* end > l1.end */ {
l1.highlightBeat(beat);
l1.highlightBeat(beat, start, duration);
this.addBeat(beat, l1.end, end - l1.end);
}
}
Expand Down
7 changes: 2 additions & 5 deletions src/midi/MidiFileGenerator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -289,15 +289,12 @@ export class MidiFileGenerator {
}
}

const realTickOffset: number = !beat.nextBeat
? audioDuration
: beat.nextBeat.absolutePlaybackStart - beat.absolutePlaybackStart;
// in case of normal playback register playback
if (realBar === beat.voice.bar) {
this.tickLookup.addBeat(beat, beatStart, realTickOffset > audioDuration ? realTickOffset : audioDuration);
this.tickLookup.addBeat(beat, beatStart, audioDuration);
} else {
// in case of simile marks where we repeat we also register
this.tickLookup.addBeat(beat, 0, realTickOffset > audioDuration ? realTickOffset : audioDuration);
this.tickLookup.addBeat(beat, 0, audioDuration);
}

const track: Track = beat.voice.bar.staff.track;
Expand Down
56 changes: 41 additions & 15 deletions src/midi/MidiTickLookup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ export class MidiTickLookup {
current.masterBar,
current.beatLookup.nextBeat,
current.end, trackLookup, false, true);

if (current.nextBeat == null) {
current.nextBeat = this.findBeatSlow(trackLookup, current, current.end, true);
}
Expand All @@ -164,6 +165,12 @@ export class MidiTickLookup {
current.tickDuration = current.nextBeat.start - current.start;
current.duration = MidiUtils.ticksToMillis(current.tickDuration, current.masterBar.tempo);
}

// no next beat, animate to the end of the bar (could be an incomplete bar)
if (!current.nextBeat) {
current.tickDuration = current.masterBar.end - current.start;
current.duration = MidiUtils.ticksToMillis(current.tickDuration, current.masterBar.tempo);
}
}

private findBeatSlow(trackLookup: Set<number>, currentBeatHint: MidiTickLookupFindBeatResult | null, tick: number, isNextSearch: boolean): MidiTickLookupFindBeatResult | null {
Expand Down Expand Up @@ -252,29 +259,47 @@ export class MidiTickLookup {
if (!startBeat) {

if (isNextSeach) {
while (currentStartLookup != null) {
startBeat = currentStartLookup.getVisibleBeatAtStart(visibleTracks);

if (startBeat) {
startBeatLookup = currentStartLookup;
break;
let currentMasterBar: MasterBarTickLookup | null = masterBar;
while (currentMasterBar != null && startBeat == null) {
while (currentStartLookup != null) {
startBeat = currentStartLookup.getVisibleBeatAtStart(visibleTracks);

if (startBeat) {
startBeatLookup = currentStartLookup;
masterBar = currentMasterBar;
break;
}

currentStartLookup = currentStartLookup.nextBeat;
}

currentStartLookup = currentStartLookup.nextBeat;
if (!startBeat || !startBeatLookup) {
currentMasterBar = currentMasterBar.nextMasterBar;
currentStartLookup = currentMasterBar?.firstBeat ?? null;
}
}
} else {
while (currentStartLookup != null) {
startBeat = currentStartLookup.getVisibleBeatAtStart(visibleTracks);

if (startBeat) {
startBeatLookup = currentStartLookup;
break;
} else {
let currentMasterBar: MasterBarTickLookup | null = masterBar;
while (currentMasterBar != null && startBeat == null) {
while (currentStartLookup != null) {
startBeat = currentStartLookup.getVisibleBeatAtStart(visibleTracks);

if (startBeat) {
startBeatLookup = currentStartLookup;
masterBar = currentMasterBar;
break;
}

currentStartLookup = currentStartLookup.previousBeat;
}

currentStartLookup = currentStartLookup.previousBeat;
if (!startBeat || !startBeatLookup) {
currentMasterBar = currentMasterBar.previousMasterBar;
currentStartLookup = currentMasterBar?.firstBeat ?? null;
}
}
}

}
} else if (currentStartLookup.end > relativeTick) {
break;
Expand Down Expand Up @@ -382,6 +407,7 @@ export class MidiTickLookup {
public addMasterBar(masterBar: MasterBarTickLookup): void {
this.masterBars.push(masterBar);
if (this._currentMasterBar) {
masterBar.previousMasterBar = this._currentMasterBar;
this._currentMasterBar.nextMasterBar = masterBar;
}
this._currentMasterBar = masterBar;
Expand Down
Loading

0 comments on commit 398064a

Please sign in to comment.