UNPKG

mscx2ly

Version:

Tool to render lilypond code from a MuseScore save file

129 lines (122 loc) 4.33 kB
import { convertMSCX2LY } from './lib.js'; import fs from 'fs'; import xml2js from 'xml2js'; import { XmlWrapper } from './xml_wrapper.js'; import admZip from 'adm-zip'; function detectVersion (data) { const createdWith = data.get('programVersion'); const [ programMajor, programMinor, programPatch] = createdWith.split('.'); const formatVersion = data.get('version'); const [ formatMajor, formatMinor] = formatVersion.split('.'); return { createdWith: { major: parseInt(programMajor, 10), minor: parseInt(programMinor, 10), patch: parseInt(programPatch, 10), text: createdWith }, formatVersion: { major: parseInt(formatMajor, 10), minor: parseInt(formatMinor, 10), text: formatVersion } }; } export const mscx2ly = async ({ sourceFile, outputFile, separateMusic, separateScore, separateParts, musicFile, scoreFile, partsFile, omitMusic, omitScore, omitParts, renderingOptions, }) => { // decide filenames if (separateMusic && !musicFile) { musicFile = `${outputFile}_music.ly`; } if (separateScore && !scoreFile) { scoreFile = `${outputFile}_score.ly`; } if (separateParts && !partsFile) { partsFile = `${outputFile}_parts.ly`; } // we first try to read the source file as a zip // if that fails, we assume it is a text file let source; try { const zip = new admZip(sourceFile); const zipEntries = zip.getEntries(); const mscxEntry = zipEntries.find(entry => entry.entryName.endsWith('.mscx')); // read source file // const source = fs.readFileSync(sourceFile, 'utf8'); source = zip.readAsText(mscxEntry); } catch (e) { // console.log('Could not read source file as zip. Assuming it is an uncompressed MuseScore file.'); source = fs.readFileSync(sourceFile, 'utf8'); } let json; try { // convert to json const parser = new xml2js.Parser({ preserveChildrenOrder : true, explicitChildren: true}); json = await parser.parseStringPromise(source); } catch (e) { console.error('Could not parse source file. Is it a MuseScore file? Exiting.'); process.exit(1); } let result; try { // convert to a format we can interact with const data = new XmlWrapper(json.museScore); const versions = detectVersion(data); if (versions.createdWith.major < 4 || versions.formatVersion.major < 4) { console.warn(`This file was created with an older version of MuseScore ${versions.createdWith.text}. Fingers crossed!`); } result = convertMSCX2LY(data, renderingOptions); } catch (e) { const errorlog = e.stack; fs.writeFileSync('error.log', errorlog); console.error('mscx2ly encountered an error during the conversion process. Please report this issue on Github:'); console.error('https://github.com/mauritslamers/mscx2ly/issues'); console.error('Please include the generated error.log file and if possible the source file. Thank you!'); process.exit(1); } try { // write output let main = '\\version "2.24.0"\n\n'; if (!separateMusic && !omitMusic) { main += result.music + "\n"; } if (!separateScore && !omitScore) { main += result.score + "\n"; } if (!separateParts && !omitParts) { main += result.parts; } fs.writeFileSync(outputFile, main); if (separateMusic && !omitMusic) { fs.writeFileSync(musicFile, result.music); } if (separateScore && !omitScore) { fs.writeFileSync(scoreFile, result.score); } if (separateParts && !omitParts) { fs.writeFileSync(partsFile, result.parts); } console.log('Conversion complete'); process.exit(0); } catch (e) { console.log(e); console.error('Could not write output files. Exiting.'); process.exit(1); } }