musescore-downloader/src/mscore.ts

137 lines
4 KiB
TypeScript
Raw Normal View History

2020-11-24 09:36:01 +00:00
/* eslint-disable @typescript-eslint/no-var-requires */
2020-11-24 11:03:46 +00:00
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
import { fetchMscz } from './mscz'
2020-10-20 05:39:38 +00:00
import { fetchData } from './utils'
2020-11-24 09:36:01 +00:00
import { ScoreInfo } from './scoreinfo'
2020-11-24 10:08:18 +00:00
import isNodeJs from 'detect-node'
2020-11-24 11:03:46 +00:00
import i18n from './i18n'
2021-01-05 14:13:00 +00:00
const WEBMSCORE_URL = 'https://cdn.jsdelivr.net/npm/webmscore@0.16/webmscore.js'
// fonts for Chinese characters (CN) and Korean hangul (KR)
// JP characters are included in the CN font
const FONT_URLS = ['CN', 'KR'].map(l => `https://cdn.jsdelivr.net/npm/@librescore/fonts/SourceHanSans${l}-Regular.woff2`)
2020-10-20 05:58:39 +00:00
const SF3_URL = 'https://cdn.jsdelivr.net/npm/@librescore/sf3/FluidR3Mono_GM.sf3'
const SOUND_FONT_LOADED = Symbol('SoundFont loaded')
export type WebMscore = import('webmscore').default
2020-11-24 09:36:01 +00:00
export type WebMscoreConstr = typeof import('webmscore').default
2020-11-24 10:08:18 +00:00
const initMscore = async (w: Window): Promise<WebMscoreConstr> => {
if (!isNodeJs) { // attached to a page
2020-11-24 09:36:01 +00:00
if (!w['WebMscore']) {
// init webmscore (https://github.com/LibreScore/webmscore)
const script = w.document.createElement('script')
script.src = WEBMSCORE_URL
w.document.body.append(script)
await new Promise(resolve => { script.onload = resolve })
}
return w['WebMscore'] as WebMscoreConstr
} else { // nodejs
return require('webmscore').default as WebMscoreConstr
}
}
let fonts: Promise<Uint8Array[]> | undefined
2020-11-24 10:08:18 +00:00
const initFonts = () => {
// load CJK fonts
// CJK (East Asian) characters will be rendered as "tofu" if there is no font
if (!fonts) {
2020-11-24 10:08:18 +00:00
if (isNodeJs) {
2020-11-24 09:36:01 +00:00
// module.exports.CN = ..., module.exports.KR = ...
const FONTS = Object.values(require('@librescore/fonts'))
const fs = require('fs')
fonts = Promise.all(
FONTS.map((path: string) => fs.promises.readFile(path) as Promise<Buffer>),
)
} else {
fonts = Promise.all(
FONT_URLS.map(url => fetchData(url)),
)
}
}
}
2020-10-20 05:58:39 +00:00
export const loadSoundFont = (score: WebMscore): Promise<void> => {
if (!score[SOUND_FONT_LOADED]) {
const loadPromise = (async () => {
2020-11-24 10:22:56 +00:00
let data: Uint8Array
if (isNodeJs) {
// module.exports.FluidR3Mono = ...
const SF3 = Object.values(require('@librescore/sf3'))[0]
const fs = require('fs')
data = await fs.promises.readFile(SF3)
} else {
data = await fetchData(SF3_URL)
}
2020-10-20 05:58:39 +00:00
await score.setSoundFont(
2020-11-24 10:22:56 +00:00
data,
2020-10-20 05:58:39 +00:00
)
})()
score[SOUND_FONT_LOADED] = loadPromise
}
return score[SOUND_FONT_LOADED] as Promise<void>
}
2020-11-24 09:36:01 +00:00
export const loadMscore = async (scoreinfo: ScoreInfo, w?: Window): Promise<WebMscore> => {
2020-11-24 10:08:18 +00:00
initFonts()
const WebMscore = await initMscore(w!)
// parse mscz data
const data = new Uint8Array(
2020-11-24 09:36:01 +00:00
new Uint8Array(await fetchMscz(scoreinfo)), // copy its ArrayBuffer
)
const score = await WebMscore.load('mscz', data, await fonts)
await score.generateExcerpts()
return score
}
2020-11-24 11:03:46 +00:00
export interface IndividualDownload {
name: string;
fileExt: string;
action (score: WebMscore): Promise<Uint8Array>;
}
export const INDV_DOWNLOADS: IndividualDownload[] = [
{
name: i18n('DOWNLOAD')('PDF'),
fileExt: 'pdf',
action: (score) => score.savePdf(),
},
{
name: i18n('DOWNLOAD')('MSCZ'),
fileExt: 'mscz',
action: (score) => score.saveMsc('mscz'),
},
{
name: i18n('DOWNLOAD')('MusicXML'),
fileExt: 'mxl',
action: (score) => score.saveMxl(),
},
{
name: i18n('DOWNLOAD')('MIDI'),
fileExt: 'mid',
action: (score) => score.saveMidi(true, true),
},
2020-12-14 07:13:20 +00:00
{
name: i18n('DOWNLOAD_AUDIO')('MP3'),
fileExt: 'mp3',
action: (score) => loadSoundFont(score).then(() => score.saveAudio('mp3')),
},
2020-11-24 11:03:46 +00:00
{
name: i18n('DOWNLOAD_AUDIO')('FLAC'),
fileExt: 'flac',
action: (score) => loadSoundFont(score).then(() => score.saveAudio('flac')),
},
{
name: i18n('DOWNLOAD_AUDIO')('OGG'),
fileExt: 'ogg',
action: (score) => loadSoundFont(score).then(() => score.saveAudio('ogg')),
},
]