Parcourir la source

feat: 支持渲染evxml的曲谱

TIANYONG il y a 1 an
Parent
commit
0e62212adb
2 fichiers modifiés avec 34 ajouts et 1 suppressions
  1. 28 0
      src/helpers/formateMusic.ts
  2. 6 1
      src/state.ts

+ 28 - 0
src/helpers/formateMusic.ts

@@ -614,6 +614,7 @@ export const formatZoom = (num = 1) => {
  * 1.全休止符的小节,没有音符默认加个全休止符
  */
 export const formatXML = (xml: string): string => {
+	console.log(11111)
 	if (!xml) return "";
 	const xmlParse = new DOMParser().parseFromString(xml, "text/xml");
 	const measures = Array.from(xmlParse.getElementsByTagName("measure"));
@@ -621,6 +622,8 @@ export const formatXML = (xml: string): string => {
 	compatibleXmlPitchVoice(xmlParse);
 	// 处理重复小节信息
 	parseXmlToRepeat(repeats)
+	// 解析处理evxml
+	analyzeEvxml(xmlParse);
 	// const words: any = xmlParse.getElementsByTagName("words");
 	// for (const word of words) {
 	// 	if (word && word.textContent?.trim() === "筒音作5") {
@@ -644,6 +647,15 @@ export const formatXML = (xml: string): string => {
 		  speed = Number(measure.getElementsByTagName('per-minute')[0]?.textContent)
 		}
 		const divisions = parseInt(measure.getElementsByTagName("divisions")[0]?.textContent || "256");
+		// 如果note节点里面有space节点,并且没有duration节点,代表这是一个空白节点,需要删除
+		if (measure.getElementsByTagName("note").length) {
+			const noteList = Array.from(measure.getElementsByTagName("note")) || [];
+			noteList.forEach((note: any) => {
+				if (note.getElementsByTagName("space").length && !note.getElementsByTagName("duration").length) {
+					measure.removeChild(note);
+				}
+			});
+		}
 		if (measure.getElementsByTagName("note").length === 0) {
 			const forwardTimeElement = measure.getElementsByTagName("forward")[0]?.getElementsByTagName("duration")[0];
 			if (forwardTimeElement) {
@@ -1037,6 +1049,13 @@ export const formateTimes = (osmd: OpenSheetMusicDisplay) => {
 					// difftime = iterator.currentTimeStamp.realValue * formatBeatUnit(beatUnit) * (60 / beatSpeed);
 					// fixtime += difftime;
 				}
+
+				// 如果是evxml,fixtime取读取xml的值
+				if (state.isEvxml) {
+					fixtime = state.evXmlBeginTime ? state.evXmlBeginTime : fixtime
+					state.fixtime = fixtime
+				}
+				console.log('节拍器时间',fixtime,state.evXmlBeginTime)
 			}
 			let stave = activeVerticalMeasureList[0]?.stave;
 
@@ -1218,6 +1237,15 @@ export const verifyCanRepeat = (startNum: number, endNum: number) => {
 	}
 }
 
+// 计算evxml的起始播放时间
+const analyzeEvxml = (xmlParse: any) => {
+	// xml拍号数
+	const xmlNum = xmlParse.getElementsByTagName("timegap")[0]?.getElementsByTagName("values")[0]?.getElementsByTagName("item")[0]?.getAttribute('num');
+	// 第一个音符的起始时间
+	const firstNoteBeginTime = xmlParse.getElementsByTagName("times")[0]?.getElementsByTagName("time")[0]?.getAttribute('begin');
+	state.evXmlBeginTime = firstNoteBeginTime ? firstNoteBeginTime / 1000 : xmlNum ? 60 / state.originSpeed * xmlNum : 0;
+}
+
 /**
  * 兼容处理xml声部移调
  * 打谱软件可能会自动处理移调,这类型的xml就不用通过程序移调了

+ 6 - 1
src/state.ts

@@ -374,8 +374,10 @@ const state = reactive({
   },
   /** 后台设置的基准评测频率 */
   baseFrequency: 440,
-  /** mp3节拍器的时间,统计拍数、速度计算得出 */
+  /** mp3节拍器的时间,统计拍数、速度计算得出,evxml通过读取xml元素获取 */
   fixtime: 0,
+  /** evxml等待播放的时间 */
+  evXmlBeginTime: 0,
   /** 指法信息 */
   fingeringInfo: {} as IFingering,
   /** 滚动容器的ID */
@@ -455,6 +457,8 @@ const state = reactive({
   noteDistance: 0,
   /** 一行谱运动模式,平滑移动、匀速移动 */
   moveType: "smooth" as "smooth" | "uniform",
+  /** 是否是evxml */
+  isEvxml: false,
 });
 const browserInfo = browser();
 let offset_duration = 0;
@@ -1095,6 +1099,7 @@ const setState = (data: any, index: number) => {
   }
   state.gradualTimes = state.extConfigJson.gradualTimes;
   state.repeatedBeats = state.extConfigJson.repeatedBeats || 0;
+  state.isEvxml = state.extConfigJson.isEvxml == 1 ? true : false;
   // 曲子包含节拍器,就不开启节拍器
   state.needTick = data.isUseSystemBeat && data.isPlayBeat ? true : false;
   // state.isOpenMetronome = data.isUseSystemBeat ? false : true;