import { regulateWithBeadSolver, starry } from 'starry-omr'; import * as issueMeasureService from '../services/issueMeasure.service.js'; import * as scoreService from '../services/score.service.js'; import { DbSolutionStore } from './dbSolutionStore.js'; import { getPickers } from './regulation.js'; import { broadcast, getSession, removeSession } from './regulationRegistry.js'; export async function regulateScoreWithProgress(scoreId: string): Promise { const session = getSession(scoreId); try { // 1. Read score from DB const scoreRow = await scoreService.getScore(scoreId); if (!scoreRow) throw new Error(`Score not found: ${scoreId}`); const scoreData = scoreRow.data; if (!scoreData) throw new Error(`Score has no data: ${scoreId}`); // 2. Recover with starry const score = starry.recoverJSON(scoreData, starry); // 3. Get pickers const pickers = getPickers(); if (!pickers) throw new Error('Regulation not initialized — no pickers loaded'); // Count total measures for progress tracking score.assemble(); const spartito = score.makeSpartito(); const totalMeasures = spartito.measures.length; // Discard this spartito — regulateWithBeadSolver creates its own score.spartito = undefined; if (session) session.total = totalMeasures; broadcast(scoreId, { type: 'started', scoreId, totalMeasures }); // 4. Call regulateWithBeadSolver const stat = await regulateWithBeadSolver(score, { pickers, solutionStore: DbSolutionStore, onPassStart: (pass, conditionName, pendingCount) => { const s = getSession(scoreId); if (s) { s.pass = pass; s.remaining = pendingCount; s.total = totalMeasures; } broadcast(scoreId, { type: 'progress', scoreId, pass, remaining: pendingCount, total: totalMeasures, measureIndex: -1, better: false, fine: false, error: false, }); }, onProgress: (measure, evaluation, better, { pass, remaining, total }) => { const s = getSession(scoreId); if (s) { s.pass = pass; s.remaining = remaining; s.total = total; } broadcast(scoreId, { type: 'progress', scoreId, pass, remaining, total, measureIndex: (measure as any).measureIndex, better, fine: evaluation.fine, error: evaluation.error, }); }, onSaveIssueMeasure: (data) => { issueMeasureService .upsert(scoreId, data.measureIndex, new starry.EditableMeasure(data.measure), data.status) .catch((err: any) => console.error('[regulateWithProgress] failed to save issue measure:', err)); }, }); // 5. Save regulated score back to DB await scoreService.updateScore(scoreId, { data: (score as any).toJSON() }); // 6. Broadcast completed broadcast(scoreId, { type: 'completed', scoreId, stat }); } catch (err: any) { console.error('[regulateWithProgress] error:', err); broadcast(scoreId, { type: 'error', scoreId, message: err.message || String(err) }); } finally { removeSession(scoreId); } }