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

Handle empty bars and pre-beat grace notes on new lookup logic #1347

Merged
merged 4 commits into from
Jan 21, 2024
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: 4 additions & 11 deletions src/midi/BeatTickLookup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,19 +14,12 @@ export class BeatTickLookupItem {
*/
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
playbackStart: number
) {
this.beat = beat;
this.playbackStart = playbackStart;
this.playbackDuration = playbackDuration;
}
}

Expand Down Expand Up @@ -81,13 +74,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, playbackStart: number, playbackDuration: number): void {
if (beat.isEmpty) {
public highlightBeat(beat: Beat, playbackStart: number): void {
if (beat.isEmpty && !beat.voice.isEmpty) {
return;
}
if (!this._highlightedBeats.has(beat.id)) {
this._highlightedBeats.set(beat.id, true);
this.highlightedBeats.push(new BeatTickLookupItem(beat, playbackStart, playbackDuration));
this.highlightedBeats.push(new BeatTickLookupItem(beat, playbackStart));
}
}

Expand Down
88 changes: 46 additions & 42 deletions src/midi/MasterBarTickLookup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,10 +97,14 @@ export class MasterBarTickLookup {

/**
* Adds a new beat to this masterbar following the slicing logic required by the MidiTickLookup.
* @param beat The beat to add to this masterbat
* @param beatPlaybackStart The original start of this beat. This time is relevant for highlighting.
* @param sliceStart The slice start to which this beat should be added. This time is relevant for creating new slices.
* @param sliceDuration The slice duration to which this beat should be added. This time is relevant for creating new slices.
* @returns The first item of the chain which was affected.
*/
public addBeat(beat: Beat, start: number, duration: number) {
const end = start + duration;
public addBeat(beat: Beat, beatPlaybackStart: number, sliceStart: number, sliceDuration: number) {
const end = sliceStart + sliceDuration;

// We have following scenarios we cover overall on inserts
// Technically it would be possible to merge some code paths and work with loops
Expand Down Expand Up @@ -208,29 +212,29 @@ export class MasterBarTickLookup {

// Variant A
if (this.firstBeat == null) {
const n1 = new BeatTickLookup(start, end);
n1.highlightBeat(beat, start, duration);
const n1 = new BeatTickLookup(sliceStart, end);
n1.highlightBeat(beat, beatPlaybackStart);

this.insertAfter(this.firstBeat, n1);
}
// Variant B
// Variant C
else if (start >= this.lastBeat!.end) {
else if (sliceStart >= this.lastBeat!.end) {
// using the end here allows merge of B & C
const n1 = new BeatTickLookup(this.lastBeat!.end, end);
n1.highlightBeat(beat, start, duration);
n1.highlightBeat(beat, beatPlaybackStart);

this.insertAfter(this.lastBeat, n1);
}
else {
let l1: BeatTickLookup | null = null;
if (start < this.firstBeat.start) {
if (sliceStart < this.firstBeat.start) {
l1 = this.firstBeat!;
} else {
let current: BeatTickLookup | null = this.firstBeat;
while (current != null) {
// find item where we fall into
if (start >= current.start && start < current.end) {
if (sliceStart >= current.start && sliceStart < current.end) {
l1 = current;
break;
}
Expand All @@ -245,118 +249,118 @@ export class MasterBarTickLookup {

// those scenarios should only happen if we insert before the
// first item (e.g. for grace notes starting < 0)
if (start < l1.start) {
if (sliceStart < l1.start) {
// Variant D
// Variant E
if (end == l1.start) {
// using firstBeat.start here allows merge of D & E
const n1 = new BeatTickLookup(start, l1.start);
n1.highlightBeat(beat, start, duration);
const n1 = new BeatTickLookup(sliceStart, l1.start);
n1.highlightBeat(beat, beatPlaybackStart);

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

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

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

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

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

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

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

this.insertBefore(l1, n1);

this.addBeat(beat, l1.end, end - l1.end);
this.addBeat(beat, beatPlaybackStart, l1.end, end - l1.end);
}
}
else if (start > l1.start) {
else if (sliceStart > l1.start) {
// variant I
if (end == l1.end) {
const n1 = new BeatTickLookup(l1.start, start);
const n1 = new BeatTickLookup(l1.start, sliceStart);
for (const b of l1.highlightedBeats) {
n1.highlightBeat(b.beat, b.playbackStart, b.playbackDuration);
n1.highlightBeat(b.beat, b.playbackStart);
}

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

this.insertBefore(l1, n1)
}
// Variant J
else if (end < l1.end) {
const n1 = new BeatTickLookup(l1.start, start);
const n1 = new BeatTickLookup(l1.start, sliceStart);
this.insertBefore(l1, n1)

const n2 = new BeatTickLookup(start, end);
const n2 = new BeatTickLookup(sliceStart, end);
this.insertBefore(l1, n2)

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

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

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

this.insertBefore(l1, n1);

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

l1.start = end;

this.insertBefore(l1, n1);
}
// variant N
else /* end > l1.end */ {
l1.highlightBeat(beat, start, duration);
this.addBeat(beat, l1.end, end - l1.end);
l1.highlightBeat(beat, beatPlaybackStart);
this.addBeat(beat, beatPlaybackStart, l1.end, end - l1.end);
}
}
}
Expand Down
21 changes: 20 additions & 1 deletion src/midi/MidiTickLookup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -417,6 +417,25 @@ export class MidiTickLookup {
}

public addBeat(beat: Beat, start: number, duration: number): void {
this._currentMasterBar?.addBeat(beat, start, duration);
const currentMasterBar = this._currentMasterBar;
if (currentMasterBar) {
// pre-beat grace notes at the start of the bar we also add the beat to the previous bar
if (start < 0 && currentMasterBar.previousMasterBar) {
const previousStart = currentMasterBar.previousMasterBar!.end + start;
const previousEnd = previousStart + duration;

// add to previous bar
currentMasterBar.previousMasterBar!.addBeat(beat, previousStart, previousStart, currentMasterBar.previousMasterBar!.end - previousStart);

// overlap to current bar?
if(previousEnd > currentMasterBar.previousMasterBar!.end) {
// the start is negative and representing the overlap to the previous bar.
const overlapDuration = duration + start;
currentMasterBar.addBeat(beat, start, 0, overlapDuration);
}
} else {
currentMasterBar.addBeat(beat, start, start, duration);
}
}
}
}
Loading