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();