fix: drum single hit, dedupe notes, validate role
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
This commit is contained in:
co-authored by
Claude Sonnet 5.5
parent
ec7cb0e568
commit
470e089f92
@@ -25,11 +25,15 @@ function checkGrid(v: number, what: string): void {
|
||||
/** Group by onset; length = shortest dur in group clipped to next onset; gaps become rests; padded to totalTicks. */
|
||||
function buildBeats(notes: ScoreNote[], totalTicks: number): Beat[] {
|
||||
const groups = new Map<number, ScoreNote[]>();
|
||||
const seen = new Set<string>();
|
||||
for (const n of notes) {
|
||||
const key = `${n.tick}:${n.pitch}`;
|
||||
if (seen.has(key)) continue; // exact duplicate (same tick+pitch)
|
||||
seen.add(key);
|
||||
checkGrid(n.tick, "tick");
|
||||
checkGrid(n.dur, "dur");
|
||||
if (n.dur <= 0) throw new Error("note dur must be > 0");
|
||||
if (n.tick + 0 >= totalTicks) throw new Error(`note at tick ${n.tick} beyond song end ${totalTicks}`);
|
||||
if (n.tick >= totalTicks) throw new Error(`note at tick ${n.tick} beyond song end ${totalTicks}`);
|
||||
(groups.get(n.tick) ?? groups.set(n.tick, []).get(n.tick)!).push(n);
|
||||
}
|
||||
const ticks = [...groups.keys()].sort((a, b) => a - b);
|
||||
@@ -92,7 +96,7 @@ function trackToTex(track: Track, barTicks: number, bars: number): string {
|
||||
const segEnd = Math.min(end, barEnd);
|
||||
for (const piece of decompose(segEnd - pos)) {
|
||||
const tie = !first && !drums && beat.notes.length > 0;
|
||||
const body = beat.notes.length === 0
|
||||
const body = beat.notes.length === 0 || (drums && !first)
|
||||
? "r"
|
||||
: beat.notes.length === 1 ? noteText(track, beat.notes[0]!, tie) : `(${beat.notes.map((n) => noteText(track, n, tie)).join(" ")})`;
|
||||
perBar[Math.floor(pos / barTicks)]!.push(`:${piece.div} ${body}${piece.dotted ? " {d}" : ""}`);
|
||||
|
||||
@@ -41,6 +41,8 @@ export function songToMidi(song: Song): at.midi.MidiFile {
|
||||
return midi;
|
||||
}
|
||||
|
||||
const ROLES: readonly string[] = ["guitar", "bass", "keys", "vocals", "drums"];
|
||||
|
||||
export function truthFromGp(bytes: Uint8Array): { bpm: number; timeSig: [number, number]; tracks: TruthTrack[] } {
|
||||
const score = at.importer.ScoreLoader.loadScoreFromBytes(bytes, new at.Settings());
|
||||
const bpm = score.tempo;
|
||||
@@ -73,6 +75,7 @@ export function truthFromGp(bytes: Uint8Array): { bpm: number; timeSig: [number,
|
||||
}
|
||||
}
|
||||
});
|
||||
if (!ROLES.includes(track.shortName as Role)) throw new Error(`track "${track.name}": shortName "${track.shortName}" is not a valid Role`);
|
||||
const tr: TruthTrack = { name: track.name, role: track.shortName as Role, notes };
|
||||
if (!track.isPercussion) tr.tuning = [...staff.tuning];
|
||||
return tr;
|
||||
|
||||
Reference in New Issue
Block a user