- Verovio single-system engraving, MuseScore audio/MIDI from the same source - React + Remotion player with live camera, colour and orb controls - Express pipeline, render queue and local H.264/AAC export - MIT license plus third-party notices for the reference skill
72 lines
2.8 KiB
TypeScript
72 lines
2.8 KiB
TypeScript
import fs from 'node:fs';
|
|
import path from 'node:path';
|
|
import {parseMusicXml, buildPerformanceOrder} from '../src/server/musicxml.js';
|
|
import {engraveOneLine} from '../src/server/engrave.js';
|
|
import {exportAudioAndMidi} from '../src/server/musescore.js';
|
|
import {parseMidiFile} from '../src/server/midi.js';
|
|
import {buildEvents} from '../src/server/events.js';
|
|
import {readAudioDuration} from '../src/server/audio.js';
|
|
import {DEFAULT_SETTINGS} from '../src/shared/types.js';
|
|
|
|
const demo = path.resolve('public/demo/demo.musicxml');
|
|
const outDir = path.resolve('data/check');
|
|
fs.mkdirSync(outDir, {recursive: true});
|
|
|
|
const parsed = parseMusicXml(fs.readFileSync(demo));
|
|
console.log('title', parsed.title, '| composer', parsed.composer);
|
|
console.log('parts', parsed.parts.length, 'measures', parsed.measures.length, 'notes', parsed.allNotes.length);
|
|
console.log('unsupported', parsed.unsupported);
|
|
console.log('warnings', parsed.warnings.slice(0, 5));
|
|
|
|
const performance = buildPerformanceOrder(parsed.measures, []);
|
|
console.log('performance order length', performance.order.length);
|
|
console.log('order', performance.order.map((i) => i + 1).join(', '));
|
|
|
|
const engraved = await engraveOneLine(parsed.annotatedXml);
|
|
fs.writeFileSync(path.join(outDir, 'score.svg'), engraved.svg);
|
|
console.log('svg', engraved.geometry.width, 'x', engraved.geometry.height, 'geometry notes', engraved.geometry.noteCount);
|
|
console.log('measure times', engraved.measureStartMs.size, 'note times', engraved.noteTimes.size);
|
|
|
|
console.time('musescore');
|
|
const {wav, midi} = await exportAudioAndMidi(demo, outDir);
|
|
console.timeEnd('musescore');
|
|
console.log('wav', fs.statSync(wav).size, 'midi', fs.statSync(midi).size);
|
|
|
|
const audioDuration = await readAudioDuration(wav);
|
|
const parsedMidi = parseMidiFile(midi);
|
|
console.log('audioDuration', audioDuration, 'midi notes', parsedMidi.notes.length, 'midi duration', parsedMidi.duration);
|
|
|
|
const built = buildEvents({
|
|
parsed,
|
|
engrave: engraved,
|
|
midi: parsedMidi,
|
|
performanceOrder: performance.order,
|
|
audioDuration,
|
|
settings: DEFAULT_SETTINGS,
|
|
});
|
|
console.log('events', built.events.length, 'scroll keys', built.scroll.length);
|
|
console.log('meta', JSON.stringify({...built.meta, warnings: built.meta.warnings.slice(0, 8)}, null, 2));
|
|
console.log('first events', built.events.slice(0, 8));
|
|
console.log('last events', built.events.slice(-5));
|
|
console.log('scroll head', built.scroll.slice(0, 6));
|
|
console.log('scroll tail', built.scroll.slice(-4));
|
|
|
|
fs.writeFileSync(
|
|
path.join(outDir, 'score.json'),
|
|
JSON.stringify(
|
|
{
|
|
version: 1,
|
|
meta: built.meta,
|
|
events: built.events,
|
|
activations: built.activations,
|
|
scroll: built.scroll,
|
|
svgUrl: '/jobs/check/score.svg',
|
|
audioUrl: '/jobs/check/audio.wav',
|
|
settings: DEFAULT_SETTINGS,
|
|
},
|
|
null,
|
|
2,
|
|
),
|
|
);
|
|
console.log('wrote', path.join(outDir, 'score.json'));
|