Files
fumen-measure-analyze/index.ts
2026-04-19 23:15:19 +09:00

73 lines
2.2 KiB
TypeScript

import {
TJAParser,
NoteSequence,
BPMChangeCommand,
MeasureCommand,
DelayCommand
} from "tja";
import { readFile } from "node:fs/promises";
async function main() {
const filePath = "tja/1.tja";
console.log(`Analyzing ${filePath}...`);
try {
const content = await readFile(filePath, "utf-8");
const parsed = TJAParser.parse(content);
console.log("\n--- Metadata ---");
console.log(`Title: ${parsed.title}`);
console.log(`BPM: ${parsed.bpm}`);
console.log(`Offset: ${parsed.offset}`);
console.log("\n--- Courses ---");
parsed.courses.forEach((course, index) => {
console.log(`Course ${index + 1}: ${course.difficulty} (Stars: ${course.stars})`);
const commands = course.activeCourse.getCommands();
let totalNotes = 0;
let currentTime = 0; // in seconds
let currentBPM = parsed.bpm || 120;
let currentMeasure = { numerator: 4, denominator: 4 };
commands.forEach(cmd => {
if (cmd instanceof BPMChangeCommand) {
currentBPM = cmd.bpm;
} else if (cmd instanceof MeasureCommand) {
currentMeasure = {
numerator: cmd.numerator,
denominator: cmd.denominator
};
} else if (cmd instanceof DelayCommand) {
currentTime += cmd.delay;
} else if (cmd instanceof NoteSequence) {
// Duration of one measure in seconds:
// (60 / BPM) * 4 * (numerator / denominator)
const measureDuration = (60 / currentBPM) * 4 * (currentMeasure.numerator / currentMeasure.denominator);
const notesInSequence = cmd.notes;
const noteCount = notesInSequence.length;
notesInSequence.forEach((note) => {
if (!note.isBlank && !note.isMeasureEnd) {
totalNotes++;
}
});
currentTime += measureDuration;
}
});
const nps = currentTime > 0 ? (totalNotes / currentTime).toFixed(2) : "0.00";
console.log(` Total Notes: ${totalNotes}`);
console.log(` Estimated Duration: ${currentTime.toFixed(2)}s`);
console.log(` Average NPS: ${nps}`);
});
} catch (error) {
console.error("Error analyzing TJA file:", error);
}
}
main();