import { computed, defineComponent, onMounted, reactive, ref, onUnmounted } from "vue"; import { formatXML, onlyVisible, getCustomInfo } from "../../helpers/formateMusic"; // // @ts-ignore import { OpenSheetMusicDisplay } from "/osmd-extended/src"; import state, { EnumMusicRenderType, IPlatform, resetCursorPosition } from "/src/state"; import Selection from "../selection"; import styles from "./index.module.less"; import queryString from "query-string"; import { getGradualLengthByXml } from "/src/helpers/calcSpeed"; import { resetFormate, resetGivenFormate, setGlobalMusicSheet, limitSingleSvgPageHeight } from "/src/helpers/customMusicScore" import { setGlobalData } from "/src/utils"; import { storeData } from "/src/store"; import HorizontalDragScroll from './HorizontalDragScroll'; import CombineAudio from './combineAudio'; import { getQuery } from "/src/utils/queryString"; export const musicRenderTypeKey = "musicRenderType"; export const musicData = reactive({ showSelection: false, // 可以加载点击浮层 score: "" }); /** 重新渲染曲谱 */ export const resetRenderMusicScore = (type?: string) => { const search = queryString.parse(location.search); const newSearch = queryString.stringify({ ...search, _t: Date.now(), musicRenderType: type, isSingleLine: state.isSingleLine }); location.search = "?" + newSearch; }; // 下载后的xml export const downloadXmlStr = ref("") export default defineComponent({ name: "music-score", emits: ["rendered"], props: { /** 是否渲染选择框 */ showSelection: { type: Boolean, default: true, }, renderTypeKey: { type: String, default: "", }, musicColor: { type: String, default: "", }, /** 是否渲染声轨名称 */ showPartNames: { type: Boolean, default: false, }, }, setup(props, { emit, slots, expose }) { const query: any = getQuery(); let osmd: any = null; /** 设置 曲谱模式,五线谱还是简谱 */ const setRenderType = () => { const musicRenderType: any = sessionStorage.getItem(props.renderTypeKey || musicRenderTypeKey); if (musicRenderType in EnumMusicRenderType) { state.musicRenderType = musicRenderType; } }; const getXML = async () => { // 当有下载的xml的时候直接使用,否则需要下载 if(!downloadXmlStr.value){ downloadXmlStr.value = await fetch(state.xmlUrl).then((response) => response.text()) } const xmlStr = downloadXmlStr.value; console.time('解析xml') const parseXmlInfo = getCustomInfo(xmlStr); const xml = formatXML(parseXmlInfo.parsedXML); musicData.score = state.isCombineRender ? xml : onlyVisible(xml, state.partIndex); if (state.gradualTimes) { state.gradual = getGradualLengthByXml(xml); } console.timeEnd('解析xml') }; const init = async () => { console.time("渲染加载耗时"); const container = document.getElementById("musicAndSelection"); if (!container || !musicData.score) return; setGlobalMusicSheet(); if(!osmd){ osmd = new OpenSheetMusicDisplay(container, { drawTitle: false, drawSubtitle: false, // drawMeasureNumbers: false, autoResize: false, followCursor: false, drawLyricist: false, // 渲染作曲家 drawComposer: false, // 渲染作词家 // pageBackgroundColor: '#609FCF', // autoGenerateMultipleRestMeasuresFromRestMeasures: state.isSingleLine ? false : true, // 连续休止小节是否合并显示 // darkMode: true, // 暗黑模式 // pageFormat: 'A4_P', // autoBeam: true, // drawMetronomeMarks: false, // ...this.opotions, colorStemsLikeNoteheads: true, // 是否将音符柄的颜色设置为与它们的音符头相同,默认false // drawingParameters: "compact" // 使用紧凑布局 // drawLyrics: (((!state.accompany && !state.music ) || state.playType === 'sing' || !state.isEvxml) && !state.isSimplePage) ? true : false, // 演唱模式才渲染歌词,simple页面不显示歌词 // drawPartNames: props.showPartNames, // 是否渲染声轨名称 // defaultColorMusic: props.musicColor, // 颜色 // renderSingleHorizontalStaffline: state.isSingleLine ? true : false }); } osmd.setOptions({ drawLyrics: (((!state.accompany && !state.music ) || state.playType === 'sing' || !state.isEvxml) && !state.isSimplePage) ? true : false, // 演唱模式才渲染歌词,simple页面不显示歌词 drawPartNames: props.showPartNames, // 是否渲染声轨名称 defaultColorMusic: props.musicColor, // 颜色 renderSingleHorizontalStaffline: state.isSingleLine ? true : false, autoGenerateMultipleRestMeasuresFromRestMeasures: state.setting.combineMultipleRest, // 是否自动合并休止小节 }) // osmd.EngravingRules.CompactMode = true // 紧凑模式 // osmd.EngravingRules.PageRightMargin = state.isSingleLine ? (window.innerWidth+200)/10 : 2; // osmd.EngravingRules.FixedMeasureWidth = state.isSingleLine ? true : false; // 是否固定小节的宽度(小节同一宽度渲染) //osmd.EngravingRules.PageTopMargin = state.platform === IPlatform.PC ? 0 : 1; // 老师端顶部间距 // 老师端上课页面,左右两边有功能按钮,所以左右边距需要加大 // if (state.isAttendClass && state.platform === IPlatform.PC) { // osmd.EngravingRules.PageLeftMargin = 7; // osmd.EngravingRules.PageRightMargin = 7; // } //osmd.EngravingRules.PageBottomMargin = state.platform === IPlatform.PC ? 1 : 2; if (state.isSimplePage) { osmd.EngravingRules.PageTopMargin = state.musicRenderType === 'staff' ? 2 : 4; osmd.EngravingRules.PageTopMarginNarrow = 0; osmd.EngravingRules.PageLeftMargin = 3.6; osmd.EngravingRules.PageRightMargin = 0; osmd.EngravingRules.BreathMarkDistance = 0.1; osmd.EngravingRules.PageBottomMargin = 0; } else { // osmd.EngravingRules.PageTopMargin = state.isEvaluatReport ? 7 : 3; // 顶部间距 // osmd.EngravingRules.PageTopMargin = state.isPreView ? 1 : 3; osmd.EngravingRules.PageTopMargin = (state.isPreView && state.musicRenderType === EnumMusicRenderType.staff) ? 1 : state.isPreView ? 2 : 3; osmd.EngravingRules.PageTopMarginNarrow = 3; osmd.EngravingRules.PageLeftMargin = state.isCombineRender ? 8 : 3.6; osmd.EngravingRules.PageRightMargin = 3; osmd.EngravingRules.BreathMarkDistance = 0.1; // 呼吸标记距离音符的位置,百分比 osmd.EngravingRules.PageBottomMargin = state.isSingleLine ? 2 : 18; } osmd.EngravingRules.DYMusicScoreType = state.musicRenderType === EnumMusicRenderType.staff ? "staff" : "jianpu"; // 如果为固定调,需要加入全局 if (state.musicRenderType === EnumMusicRenderType.fixedTone) { (window as any).sett = { keySignature: true, }; } else { (window as any).sett = { keySignature: false, }; } osmd.EngravingRules.DYMusicScoreId = state.examSongId || '' osmd.EngravingRules.DYCustomRepeatCount = state.maxLyricNum || 0; osmd.EngravingRules.DYIsSingleLine = state.isSingleLine; await osmd.load(musicData.score); // 对外暴露 一行谱时候 缩小谱面 if(state.isSimplePage){ state.zoom = 0.5 } // 需要渲染总谱的云教练页面 if (!state.isSimplePage && state.isCombineRender) { const canSelectTracks = state.combinePartIndexs.length > 1 ? state.combinePartIndexs.map(partIndex => { return state.partListNames[partIndex] }) : state.canSelectTracks for (let i = 0; i < osmd.Sheet.Instruments.length; i++) { const trackName = state.isEvxml && state.evxmlAddPartName ? osmd.Sheet.Instruments[i].idString || '' : osmd.Sheet.Instruments[i].Name || ''; osmd.Sheet.Instruments[i].Visible = canSelectTracks.includes(trackName.trim()) } } if (query.downPng === 'A4') { osmd.EngravingRules.PageTopMargin = 5 osmd.setPageFormat('794x1100') osmd.zoom = query.zoom || 0.3; } else { osmd.zoom = state.zoom; } osmd.render(); console.log("🚀 ~ osmd:", osmd) emit("rendered", osmd); resetFormate(); resetGivenFormate(); musicData.showSelection = true; }; let horizontalDragScroll:HorizontalDragScroll | null onMounted(async () => { //setRenderType(); await getXML(); await init(); // pc 端支持 拖动滚动 if(state.platform === "PC" || query.isCbs){ const container = document.querySelector('#musicAndSelection') as HTMLElement; horizontalDragScroll = new HorizontalDragScroll(container); } }); onUnmounted(() => { horizontalDragScroll?.destroy() }) const isInTheGradualRange = computed(() => { let result: boolean = false; const activeMeasureIndex = state.times[state.activeNoteIndex]?.measureListIndex || -1; for (const [first, last] of state.gradual) { if (first && last) { // console.log('小节',first.measureIndex,last.measureIndex,activeMeasureIndex) result = first.measureIndex <= activeMeasureIndex && activeMeasureIndex < last.measureIndex; if (result) { break; } } } return result; }); /** 刷新曲谱 */ const refreshMusicScore = () => { state.loadingText = "正在加载中,请稍等..." state.isLoading = true state.evXmlBeginArr = []; state.vfmeasures = []; state.activeNoteIndex = 0; musicData.showSelection = false; state.osmd.clear(); const container = document.getElementById('musicAndSelection'), svgDom = document.getElementById('osmdCanvasPage1'); if (container) { //这里需要删除osmd,不然多行谱和一行谱切换 滚动高度会出问题 svgDom && container?.removeChild(svgDom) } // 有可能会有 其他地方的js执行 阻塞 这里确保加载条出来 setTimeout(async () => { // 在滚动过程中(雄鹰高飞这种marginbottom比较大的) 多行谱和一行谱切换 滚动高度会出问题 container && (container.scrollTop = 0) //setRenderType(); state.basePlayRate = 1; await getXML(); await init(); musicData.showSelection = true; state.isLoading = false resetCursorPosition() }, 60); } expose({ refreshMusicScore, }) return () => (