123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271 |
- 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 () => (
- <div
- id="musicAndSelection"
- style={{ "--music-zoom": state.musicZoom }}
- class={[
- isInTheGradualRange.value && styles.inGradualRange,
- state.musicRenderType == EnumMusicRenderType.staff ? "staff" : "jianpuTone",
- state.isSingleLine && "singleLineMusicBox",
- (!state.isCreateImg && !state.isPreView && !state.isCbsView && state.musicRenderType === EnumMusicRenderType.staff) ? "blueMusicXml" : "",
- state.isSingleLine && state.playState ==="play" && styles.notTouch,
- !state.isSingleLine && (state.platform === "PC" || query.isCbs) && styles.pcCursorGrab
- ]}
- >
- {slots.default?.()}
- {props.showSelection && musicData.showSelection && !state.isEvaluatReport &&!state.isSimplePage && !state.isPreView && state.musicRendered && <Selection />}
- {props.showSelection && musicData.showSelection && state.isCombineRender &&!state.isSimplePage && !state.isPreView && state.musicRendered && <CombineAudio></CombineAudio> }
- </div>
- );
- },
- });
|