Quellcode durchsuchen

Merge branch 'feature-tianyong-newVersion' of http://git.dayaedu.com/liushengqiang/music-score into hqyDevNewVersion

黄琪勇 vor 11 Monaten
Ursprung
Commit
5b3112e56f

+ 1 - 1
osmd-extended

@@ -1 +1 @@
-Subproject commit 331c4861934bbdc6b63c210308fc18f92a80c178
+Subproject commit 4a5ed1ea08671c9db6789080376ad4c67ef49695

+ 23 - 7
src/helpers/formateMusic.ts

@@ -623,7 +623,30 @@ export const formatXML = (xml: string, xmlUrl?: string): string => {
 	if (!xml) return "";
 	
 	const xmlParse = new DOMParser().parseFromString(xml, "text/xml");
+
 	const measures = Array.from(xmlParse.getElementsByTagName("measure"));
+	const minutes: any = xmlParse.getElementsByTagName("per-minute");
+	let speeds: any = []
+	for (const minute of minutes) {
+		if (minute.textContent && !!Number(minute.textContent)) {
+			speeds.push(Number(minute.textContent))
+		}
+	}
+	speeds = [...new Set(speeds)]
+	const hasVaryingSpeed = speeds.length > 1 ? true : false
+  // 如果后台没有设置速度,默认取xml速度,如果xml也没有速度,默认赋值100
+	if (state.originSpeed === 0) {
+		state.originSpeed = speeds[0] ? speeds[0] : 100;
+		state.speed = state.originSpeed;
+	}
+	// 如果谱面和小节都没有打速度,osmd设置的小节速度默认取后台设置的速度
+	if (speeds.length === 0) {
+		;(window as any).baseMeasureSpeed = state.originSpeed
+	} else {
+		state.originAudioPlayRate = speeds[0] / state.originSpeed
+	}
+	console.log('是否是变速的曲子:',hasVaryingSpeed,speeds)
+
 	const repeats: any = Array.from(xmlParse.querySelectorAll('repeat'));
 	compatibleXmlPitchVoice(xmlParse);
 	// 获取作词、作曲家
@@ -705,13 +728,6 @@ export const formatXML = (xml: string, xmlUrl?: string): string => {
         </note>`;
 		}
 	}
-	// 如果曲谱详情接口没有返回速度,则取xml第一小节的速度,如果取不到,则取默认速度:100
-	if (!speed || speed == -1) {
-		speed = 100
-	}
-	if (!state.originSpeed) {
-		state.originSpeed = state.speed = speed || 100
-	}
 	return new XMLSerializer().serializeToString(xmlParse);
 };
 

+ 1 - 1
src/helpers/metronome.ts

@@ -199,7 +199,7 @@ class Metronome {
 				return
 			}			
 		}
-		console.log("播放自带的节拍器 233333")
+		// console.log("播放自带的节拍器 233333")
 		if (!metronomeData.initPlayerState || state.playState === 'paused') return;
 		const beatVolume = state.setting.beatVolume / 100
 		// this.source = metronomeData.activeMetro?.index === 0 ? this.source1 : this.source2;

+ 2 - 2
src/page-instrument/header-top/index.tsx

@@ -79,7 +79,7 @@ export const headTopData = reactive({
       state.playIngSpeed = state.originSpeed;
       handleStartEvaluat();
       // 开发模式,把此处打开
-      state.modeType = "evaluating"
+      // state.modeType = "evaluating"
       // evaluatingData.rendered = true;
       // evaluatingData.soundEffectMode = true;
     } else if (value === "follow") {
@@ -329,7 +329,7 @@ export default defineComponent({
     /** 选段按钮 */
     const selectBtn = computed(() => {
       // 选择模式 不显示
-      if (headTopData.modeType !== "show" || ["evaluating", "follow"].includes(state.modeType)) return { display: false, disabled: true };
+      if (headTopData.modeType !== "show" || ["follow"].includes(state.modeType)) return { display: false, disabled: true };
       // 音频播放中 禁用
       if (state.playState === "play") return { display: true, disabled: true };
 

+ 8 - 0
src/page-instrument/header-top/speed/index.tsx

@@ -24,6 +24,14 @@ export default defineComponent({
 				handleSetSpeed(speed.value);
 			}
 		);
+		watch(
+			() => state.speed,
+			() => {
+				if (speed.value !== state.speed) {
+					speed.value = state.speed;
+				}
+			}
+		);
 		const metronomeDisable = computed({
 			get(){
 				return !metronomeData.disable

+ 5 - 5
src/page-instrument/view-detail/index.tsx

@@ -171,11 +171,11 @@ export default defineComponent({
       if (state.originSpeed === 0) {
         state.originSpeed = state.speed = (osmd as any).bpm || osmd.Sheet.userStartTempoInBPM || 100;
       }
-      const saveSpeed = (store.get("speeds") || {})[state.examSongId] || state.speed || (osmd as any).bpm || osmd.Sheet.userStartTempoInBPM;
-      // 加载本地缓存的速度
-      if (saveSpeed) {
-        handleSetSpeed(saveSpeed);
-      }
+      // const saveSpeed = (store.get("speeds") || {})[state.examSongId] || state.speed || (osmd as any).bpm || osmd.Sheet.userStartTempoInBPM;
+      // // 加载本地缓存的速度
+      // if (saveSpeed) {
+      //   handleSetSpeed(saveSpeed);
+      // }
       setCustomGradual();
 			setCustomNoteRealValue();
       state.times = formateTimes(osmd);

+ 68 - 37
src/state.ts

@@ -504,6 +504,10 @@ const state = reactive({
   loadingText: '音频资源加载中,请稍后…',
   /** 是否是简单的单行谱模式页面 */
   isSimplePage: false, 
+  /** xml的速度和后台设置的速度,计算出的基础音频播放倍率 */
+  originAudioPlayRate: 1,  
+  /** 开始播放时,记录的mp3播放倍率,用户当前设置的速度/当前小节的速度 */
+  basePlayRate: 1,
 });
 const browserInfo = browser();
 let offset_duration = 0;
@@ -579,6 +583,35 @@ export const onEnded = () => {
   autoResetPlay();
 };
 
+// 根据当前小节动态设置,右上角展示的速度
+const dynamicShowPlaySpeed = (index: number) => {
+  const item: any = state.times[index];
+  if (item && item.measureSpeed ) {
+    state.playIngSpeed = Math.floor(state.basePlayRate * item.measureSpeed)
+    state.speed = state.playIngSpeed
+  }
+}
+
+// 开始播放时,计算mp3的播放倍率
+export const initSetPlayRate = () => {
+  const item: any = (state.sectionStatus && state.section.length === 2) ? state.sectionFirst || state.section[0] : state.times[state.activeNoteIndex];
+  if (item && item.measureSpeed) {
+    const ratio = state.speed / item.measureSpeed
+    // state.audiosInstance?.setSpeed(ratio)
+    state.basePlayRate = ratio || 1;
+    console.log('播放倍率',state.basePlayRate)
+  }
+}
+
+// 重置播放倍率
+export const resetBaseRate = () => {
+  const currentItem: any = state.times[0];
+  const currentSpeed = currentItem?.measureSpeed ? currentItem.measureSpeed : state.originSpeed;
+  state.speed = currentSpeed
+  //state.activeNoteIndex = 0
+  state.basePlayRate = 1;
+}
+
 /**
  * 播放一直触发的事件
  */
@@ -587,17 +620,8 @@ const handlePlaying = () => {
   const duration = getAudioDuration();
   state.playProgress = (currentTime / duration) * 100;
   let item = getNote(currentTime);
-  // console.log(11111,currentTime,duration,state.playSource, item)
-  // console.log(item?.i,item?.noteId,item?.measureSpeed,'播放')
-  // 练习模式下,实时刷新小节速度
-  if (item && state.modeType === "practise" && state.playState === "play" && item.measureSpeed && item.measureSpeed !== state.playIngSpeed) {
-    const ratio = state.speed / state.originSpeed
-    state.playIngSpeed = Math.ceil(ratio * item.measureSpeed) || state.speed
-  } else if (state.modeType === "practise" && state.playState === "play" && item && !item.measureSpeed) {
-    state.playIngSpeed = state.speed
-  }
-  state.playIngSpeed = state.playIngSpeed || state.speed;
   if (item) {
+    dynamicShowPlaySpeed(item.i);
     // 选段状态下
     if (state.sectionStatus && state.section.length === 2) {
       // 如果开启了预备拍
@@ -640,6 +664,8 @@ const handlePlaying = () => {
         // #8698 bug修复
         if (state.modeType === "practise" && state.sectionStatus) {
           onEnded();
+          state.activeNoteIndex = state.sectionFirst ? state.sectionFirst.i : state.section[0].i
+          dynamicShowPlaySpeed(state.activeNoteIndex)
           resetPlaybackToStart();
           return;
         }
@@ -669,6 +695,10 @@ export const skipNotePlay = async (itemIndex: number, isStart = false) => {
     itemTime = 0;
   }
   if (item) {
+    // 非选段模式,点击音符,动态设置右下角的速度
+    if (item.measureSpeed && state.section.length < 2) {
+      state.speed = Math.floor(state.basePlayRate * item.measureSpeed)
+    }
     setAudioCurrentTime(itemTime, itemIndex);
     // 一行谱,点击音符,或者播放完成,需要跳转音符位置
     gotoNext(item, true);
@@ -752,6 +782,7 @@ export const togglePlay = async (playState?: "play" | "paused", sourceType?: str
       clearSelection();
     }
   }
+  initSetPlayRate();
   audioListStart(state.playState);
   return true;
 };
@@ -994,14 +1025,20 @@ export const handleResetPlay = () => {
   if (state.isAppPlay) {
     audioData.progress = 0
   }
+  resetBaseRate();
   resetPlaybackToStart();
   // 如果是暂停, 直接播放
   togglePlay("play");
 };
 /** 设置速度 */
 export const handleSetSpeed = (speed: number) => {
-  setStorageSpeed(state.examSongId, speed);
+  // setStorageSpeed(state.examSongId, speed);
   state.speed = speed;
+  // 当前的音符
+  const currentItem: any = (state.sectionStatus && state.section.length === 2) ? state.sectionFirst || state.section[0] : state.times[state.activeNoteIndex];
+  state.basePlayRate = currentItem?.measureSpeed ? state.speed / currentItem.measureSpeed : state.speed / state.originSpeed;
+  const actualRate = state.originAudioPlayRate * state.basePlayRate;
+  console.log('速度设置',speed,'小节计算的倍率',state.basePlayRate,'实际播放倍率',actualRate)
 };
 /** 清除选段状态 */
 export const clearSelection = () => {
@@ -1352,7 +1389,7 @@ const setState = (data: any, index: number) => {
   if (state.isAppPlay) {
     state.enableEvaluation = state.midiUrl ? true : false
   } else {
-    state.enableEvaluation = state.accompany ? true : false
+    state.enableEvaluation = state.accompany || state.music ? true : false
   }
   state.isConcert = data.musicSheetType === "CONCERT" ? true : false;
   // multiTracksSelection 返回为空,默认代表全部分轨
@@ -1620,11 +1657,12 @@ watch(
 	() => state.activeMeasureIndex,
 	() => {
     // 需要减去的合并小节数
-    const needReduceMultipleRestNum = getNeedReduceMultipleRestNum(state.activeMeasureIndex)
-    const matchMeasureNum = state.activeMeasureIndex - needReduceMultipleRestNum - 1
-    console.log('选中的小节',matchMeasureNum,'需要减去的小节',needReduceMultipleRestNum,'当前的小节',state.activeMeasureIndex)
+    // const needReduceMultipleRestNum = getNeedReduceMultipleRestNum(state.activeMeasureIndex)
+    // const matchMeasureNum = state.activeMeasureIndex - needReduceMultipleRestNum - 1
+    // console.log('选中的小节',matchMeasureNum,'需要减去的小节',needReduceMultipleRestNum,'当前的小节',state.activeMeasureIndex)
     state.vfmeasures.forEach((item: any, idx: number) => {
-      if (idx === matchMeasureNum) {
+      const measureNum = item.getAttribute('data-num') ? Number(item.getAttribute('data-num')) : 1;
+      if (measureNum === state.activeMeasureIndex) {
         item.querySelector('.vf-custom-bg')?.setAttribute("fill", "#132D4C")
         item.querySelector('.vf-custom-bot')?.setAttribute("fill", "#040D1E")
       } else {
@@ -1637,18 +1675,14 @@ watch(
             leftMeasureNumberXML = state.section[1].MeasureNumberXML
             rightMeasureNumberXML = state.section[0].MeasureNumberXML
           }
-          const leftVfmeasuresIndex = leftMeasureNumberXML - getNeedReduceMultipleRestNum(leftMeasureNumberXML) - 1
-          const rightVfmeasuresIndex = rightMeasureNumberXML - getNeedReduceMultipleRestNum(rightMeasureNumberXML) - 1
-          if(idx >= leftVfmeasuresIndex && idx <= rightVfmeasuresIndex){
+          if(measureNum >= leftMeasureNumberXML && measureNum <= rightMeasureNumberXML){
             item.querySelector('.vf-custom-bg')?.setAttribute("fill", "#609FCF")
             item.querySelector('.vf-custom-bot')?.setAttribute("fill", "#2B70A5")
           }
           // 预备小节
-          if(state.sectionFirst){
-            const sectionFirstVfmeasuresIndex = state.sectionFirst.MeasureNumberXML - getNeedReduceMultipleRestNum(state.sectionFirst.MeasureNumberXML) - 1
-            const sectionFirstDom = state.vfmeasures[sectionFirstVfmeasuresIndex]
-            sectionFirstDom?.querySelector('.vf-custom-bg')?.setAttribute("fill", "#71B8BD")
-            sectionFirstDom?.querySelector('.vf-custom-bot')?.setAttribute("fill", "#448F9C")
+          if(state.sectionFirst && measureNum === state.sectionFirst.MeasureNumberXML){
+            item?.querySelector('.vf-custom-bg')?.setAttribute("fill", "#71B8BD")
+            item?.querySelector('.vf-custom-bot')?.setAttribute("fill", "#448F9C")
           }
         }else{
           item.querySelector('.vf-custom-bg')?.setAttribute("fill", "#609FCF")
@@ -1672,32 +1706,29 @@ watch(
         leftMeasureNumberXML = state.section[1].MeasureNumberXML
         rightMeasureNumberXML = state.section[0].MeasureNumberXML
       }
-      const leftVfmeasuresIndex = leftMeasureNumberXML - getNeedReduceMultipleRestNum(leftMeasureNumberXML) - 1
-      const rightVfmeasuresIndex = rightMeasureNumberXML - getNeedReduceMultipleRestNum(rightMeasureNumberXML) - 1
       state.vfmeasures.forEach((item: any, idx: number) => {
+        const measureNum = item.getAttribute('data-num') ? Number(item.getAttribute('data-num')) : 1;
         // 小于选中置灰
-        if (idx < leftVfmeasuresIndex) {
+        if (measureNum < leftMeasureNumberXML) {
           item.querySelector('.vf-custom-bg')?.setAttribute("fill", "rgba(96,159,207,0.5)")
           item.querySelector('.vf-custom-bot')?.setAttribute("fill", "rgba(43,112,165,0.5)")
         }
         // 大于选中置灰
-        if(idx > rightVfmeasuresIndex){
+        if(measureNum > rightMeasureNumberXML){
           item.querySelector('.vf-custom-bg')?.setAttribute("fill", "rgba(96,159,207,0.5)")
           item.querySelector('.vf-custom-bot')?.setAttribute("fill", "rgba(43,112,165,0.5)")
         }
+        // 预备小节
+        if(state.sectionFirst && measureNum === state.sectionFirst.MeasureNumberXML){
+          item?.querySelector('.vf-custom-bg')?.setAttribute("fill", "#71B8BD")
+          item?.querySelector('.vf-custom-bot')?.setAttribute("fill", "#448F9C")
+        }        
       })
-      // 预备小节
-      if(state.sectionFirst){
-        const sectionFirstVfmeasuresIndex = state.sectionFirst.MeasureNumberXML - getNeedReduceMultipleRestNum(state.sectionFirst.MeasureNumberXML) - 1
-        const sectionFirstDom = state.vfmeasures[sectionFirstVfmeasuresIndex]
-        sectionFirstDom?.querySelector('.vf-custom-bg')?.setAttribute("fill", "#71B8BD")
-        sectionFirstDom?.querySelector('.vf-custom-bot')?.setAttribute("fill", "#448F9C")
-      }
     }else{
       // 恢复选段前
-      const matchMeasureNum = state.activeMeasureIndex - getNeedReduceMultipleRestNum(state.activeMeasureIndex) - 1
       state.vfmeasures.forEach((item: any, idx: number) => {
-        if (idx === matchMeasureNum) {
+        const measureNum = item.getAttribute('data-num') ? Number(item.getAttribute('data-num')) : 1;
+        if (measureNum === state.activeMeasureIndex) {
           item.querySelector('.vf-custom-bg')?.setAttribute("fill", "#132D4C")
           item.querySelector('.vf-custom-bot')?.setAttribute("fill", "#040D1E")
         } else {

+ 1 - 0
src/utils/index.ts

@@ -97,6 +97,7 @@ export const setStorageSpeed = (id: any, speed: number) => {
 /** 获取曲谱速度 */
 export const getStorageSpeed = (id: any) => {
 	const speeds = store.get(SPEEDKEY) || {}
+	console.log('初始速度', speeds)
 	return speeds[id] || 0
 }
 

+ 3 - 1
src/view/audio-list/index.tsx

@@ -39,7 +39,9 @@ const midiRef = ref();
 export const audioListStart = (type: "play" | "paused") => {
 	// 开始播放之前, 先设置倍数
 	if (type === "play" && state.originSpeed !== 0) {
-		setAudioPlaybackRate(state.speed / state.originSpeed);
+		const actualRate = state.originAudioPlayRate * state.basePlayRate;
+		// console.log('音频播放倍率',actualRate)
+		setAudioPlaybackRate(actualRate);
 	}
 	// console.log('api','midi状态1',type,state.isAppPlay)
 	// 如果是midi播放

+ 0 - 26
src/view/audio-list/loading.tsx

@@ -16,32 +16,6 @@ export default defineComponent({
 		},
 	},
    setup(props) {
-      function fakeLoadingProgress(duration = 2000, callback: (num: number) => void) {
-         let startTime = Date.now()
-         let progress = 0
-         const timer = setInterval(() => {
-            let timePassed = Date.now() - startTime
-            if (timePassed >= duration) {
-               clearInterval(timer)
-               callback(96) // 进度完成
-               return
-            }
-            progress = Math.min(100, (timePassed / duration) * 100)
-            callback(progress)
-         }, 300)
-      }
-      const loadingProress = ref(0)
-      fakeLoadingProgress(2000, num => {
-         loadingProress.value = num
-      })
-      watch(
-         () => state.audioDone,
-         () => {
-           if (!state.audioDone) {
-            loadingProress.value = 0
-           }
-         }
-       );
       return () =>
          !state.audioDone && (
             <div class={styles.loadingPop}>

+ 2 - 1
src/view/evaluating/index.tsx

@@ -406,7 +406,8 @@ export const handleStartBegin = async (preTimes?: number) => {
 	let rate = state.speed / state.originSpeed;
 	rate = parseFloat(rate.toFixed(2));
 	await api_startRecordingCb({
-		accompanimentState: state.setting.enableAccompaniment ? 1 : 0,
+		// accompanimentState: state.setting.enableAccompaniment ? 1 : 0,
+		accompanimentState: !state.accompany ? 0 : 1, // 评测没有伴奏时,静音播放
 		firstNoteTime: preTimes || 0,
 		speedRate: rate, // 播放倍率
 	}, () => {

+ 1 - 1
src/view/music-score/index.module.less

@@ -30,7 +30,7 @@
         }
         transform-box: fill-box;
         transform-origin: center;
-        animation: noteAnimate 0.3s linear;
+        // animation: noteAnimate 0.3s linear;
         // transform: scale(2);
         // transition: all 0.3s;
     }