瀏覽代碼

Merge branch 'feature-pc-choose' into gyt-test

TIANYONG 10 月之前
父節點
當前提交
637d7be50e

+ 3 - 1
src/pages/detail/helpers.ts

@@ -1125,6 +1125,8 @@ export const formatXML = (xml: string, initInfo?: InitXmlInfo): string => {
 	// 如果谱面和小节都没有打速度,osmd设置的小节速度默认取后台设置的速度
 	if (speeds.length === 0) {
 		;(window as any).baseMeasureSpeed = state.baseSpeed
+	} else {
+		runtime.originAudioPlayRate = speeds[0] / state.baseSpeed
 	}
 	console.log('是否是变速的曲子:',hasVaryingSpeed,speeds)
 
@@ -1593,7 +1595,7 @@ export const setSettionBackground = () => {
     const measureListIndex = activeNote.sourceMeasure.measureListIndex
 
     // 如果没有节拍器,默认提前一个小节
-    if (index === 0 && measureListIndex !== 0 && !state.needTick) {
+    if (index === 0 && measureListIndex !== 0) {
       const firstNote = getFirsrNoteByMeasureListIndex(measureListIndex - 1)
       const fnote = firstNote?.noteElement
       if (fnote) {

+ 34 - 17
src/pages/detail/runtime.ts

@@ -140,6 +140,8 @@ const state = reactive({
   } as {[key: string]: () => void},  
   /** 阶段评测,延迟检测是否检测过 */
   delayCheckFirst: false,  
+  /** xml的速度和后台设置的速度,计算出的基础音频播放倍率 */
+  originAudioPlayRate: 1,  
   /** 开始播放时,记录的mp3播放倍率,用户当前设置的速度/当前小节的速度 */
   basePlayRate: 1,
   /** 播放中,更加当前小节速度动态计算的展示速度 */
@@ -335,10 +337,12 @@ export const changeSpeed = (speed: number, isSave: boolean = true) => {
   state.speed = speed
   state.playIngSpeed = speed
   // 当前的音符
-  const currentItem: any = (detailState.sectionStatus && detailState.section.length === 2) ? detailState.section[0] : detailState.times[state.activeIndex];
+  const currentItem: any = (detailState.sectionStatus && detailState.section.length === 2) ? detailState.befireSection || detailState.section[0] : detailState.times[state.activeIndex];
   state.basePlayRate = currentItem?.measureSpeed ? state.speed / currentItem.measureSpeed : state.speed / detailState.baseSpeed;
+  const actualRate = state.originAudioPlayRate * state.basePlayRate;
   if (!detailState.activeDetail) return
-  state.audiosInstance?.setSpeed(state.basePlayRate)
+  state.audiosInstance?.setSpeed(actualRate)
+  console.log('速度设置',speed,isSave,'小节计算的倍率',state.basePlayRate,'实际播放倍率',actualRate)
   promisefiyPostMessage({
     api: 'cloudChangeSpeed',
     content: {
@@ -364,7 +368,8 @@ export const resetCursor = () => {
     } else {
       state.osmd.cursor.reset()
     }
-    state.osmd.cursor.hide()
+    // 隐藏音符指针
+    // state.osmd.cursor.hide()
     detailState.fixedKey = 0
   }
 }
@@ -400,8 +405,8 @@ export const refreshIndexBase = (index: number) => {
 
 // 练习模式下,开始播放时,记录mp3的播放倍率
 export const initSetPlayRate = () => {
-  const item: any = (detailState.sectionStatus && detailState.section.length === 2) ? detailState.section[0] : detailState.times[state.activeIndex];
-  if (item && modelType.value === "practice" && item.measureSpeed) {
+  const item: any = (detailState.sectionStatus && detailState.section.length === 2) ? detailState.befireSection || detailState.section[0] : detailState.times[state.activeIndex];
+  if (item && item.measureSpeed) {
     const ratio = state.speed / item.measureSpeed
     // state.audiosInstance?.setSpeed(ratio)
     state.basePlayRate = ratio || 1;
@@ -418,6 +423,7 @@ const dynamicShowPlaySpeed = (index: number) => {
   // }
   if (item && item.measureSpeed ) {
     state.playIngSpeed = Math.floor(state.basePlayRate * item.measureSpeed)
+    state.speed = state.playIngSpeed
   }
 }
 
@@ -539,6 +545,8 @@ export const refreshPlayer = async (ctime?: number) => {
       setTimeout(() => {
         // 开启了循环播放
         if (detailState.section.length && SettingState.sett.loop){
+          state.activeIndex = detailState.befireSection ? detailState.befireSection.i : detailState.section[0].i
+          dynamicShowPlaySpeed(state.activeIndex)
           setPlayState()
         }
       }, 1000)
@@ -674,7 +682,7 @@ const setDelayTime = async (time: number) => {
  */
 export const pause = async () => {
   if (detailState.sectionStatus) {
-    state.osmd.cursor.hide()
+    // state.osmd.cursor.hide()
   }
   if (detailState.activeDetail.isAppPlay) {
     await syncPlayState()
@@ -704,6 +712,12 @@ export const ended = debounce(async (evt: Event, flag?: string) => {
   if (!state.evaluatingStatus) {
     refreshPlayer(0)
     if (SettingState.sett.loop || (flag && flag === 'isRePlay')) {
+      if (detailState.section.length === 2) {
+        state.activeIndex = detailState.befireSection ? detailState.befireSection.i : detailState.section[0].i
+      } else {
+        state.activeIndex = 0
+      }
+      dynamicShowPlaySpeed(state.activeIndex)
       await setPlayState()
     }
   }
@@ -790,19 +804,21 @@ export const getFirsrNoteByMeasureListIndex = (index: number, tie = true) => {
   return null
 }
 
+// 设置当前的播放时间,和光标的位置
 export const setSectionModeCurrentTime = () => {
-  if (detailState.needTick) {
-    setCurrentTime(detailState.section[0].sourceStartTime || detailState.section[0].time)
-  } else {
-    const measureListIndex = detailState.section[0].noteElement?.sourceMeasure?.measureListIndex
-    if (measureListIndex > 0) {
-      setCurrentTime(getFirsrNoteByMeasureListIndex(measureListIndex - 1).time)
-      // 如果没有节拍器,默认提前一个小节
-      // setCurrentTime(getFirsrNoteByMeasureListIndex(measureListIndex).time)
-      detailState.sectionFlash = true
-    } else {
-      setCurrentTime(0)
+  console.log(detailState.needTick, 'setSectionModeCurrentTime')
+  if (detailState.section.length === 2) {
+      // 预备小节的小节数
+    const preMeasureNum = detailState.befireSection?.measureNumberPrinted;
+    let preNoteNum = detailState.section[0].i - 1;
+    while (preMeasureNum === detailState.times[preNoteNum]?.measureNumberPrinted && preNoteNum >= 1 && preMeasureNum === detailState.times[preNoteNum-1].measureNumberPrinted) {
+      preNoteNum -= 1;
     }
+    const preTime = detailState.befireSection ? detailState.times[preNoteNum].time : detailState.section[0].time
+    detailState.sectionFlash = true
+    setCurrentTime(preTime)
+  } else {
+    setCurrentTime(0)
   }
 }
 
@@ -987,6 +1003,7 @@ export const setPlayState = async () => {
     await toggleState()
     return
   }
+  initSetPlayRate();
   setPlayerView()
   setTick(setTickStop)
 }

+ 12 - 7
src/pages/detail/section-box/index.tsx

@@ -3,7 +3,7 @@ import { defineComponent, watchEffect, TransitionGroup, ref, Ref, reactive } fro
 import event from '/src/components/music-score/event'
 import SettingState from '/src/pages/detail/setting-state'
 import state from '../state'
-import runtime, { getFirsrNoteByMeasureListIndex, getBoundingBoxByNote, changeSpeed } from '../runtime'
+import runtime, { getFirsrNoteByMeasureListIndex, getBoundingBoxByNote, changeSpeed, setStepView } from '../runtime'
 import { getActtiveNoteByTimes, getBoundingBoxByverticalNote, getNoteBySlursStart, setSettionBackground } from '../helpers'
 import { formatZoom } from '/src/helpers/utils'
 import styles from './index.module.less'
@@ -89,6 +89,10 @@ export default defineComponent({
   },
   methods: {
     setSection(evt: MouseEvent) {
+      // 已经选段后,再次点击音符直接return,不需要重新处理
+      if (state.section.length === 2) {
+        return
+      }
       const activeNote = getActtiveNoteByTimes(evt)
       if (activeNote && state.section.length < 2) {
         const sectionLength = state.section.length
@@ -99,16 +103,17 @@ export default defineComponent({
         if (sectionLength === 1) {
           const note = getNoteBySlursStart(activeNote, true, 'end')
           state.section.push(state.times[note.i - note.si + note.noteLength - 1])
-          // 选段状态需要重置播放倍率为1
-          runtime.basePlayRate = 1;
-          const currentItem: any = state.section[0];
-          const currentSpeed = currentItem?.measureSpeed ? currentItem.measureSpeed : state.activeSpeed;
-          changeSpeed(currentSpeed)
         }
       }
-      if (state.section.length === 2) {
+      if (state.section.length === 2 && runtime.playState !== 'play') {
         Toast.clear()
         setSettionBackground()
+        // 选段状态需要重置播放倍率为1
+        runtime.basePlayRate = 1;
+        const currentItem: any = state.befireSection || state.section[0];
+        const currentSpeed = currentItem?.measureSpeed ? currentItem.measureSpeed : state.activeSpeed;
+        changeSpeed(currentSpeed)
+        setStepView(currentItem)
       }
     },
     sectionClick(evt: MouseEvent): void {

+ 3 - 3
src/pages/detail/speed.tsx

@@ -147,9 +147,9 @@ export default defineComponent({
               size="mini"
               round
               onClick={() => {
-                if (detailState.activeDetail) {
-                  changeSpeed(detailState.activeDetail?.originalSpeed)
-                }
+                const currentItem: any = detailState.times[runtime.activeIndex];
+                const currentSpeed = currentItem?.measureSpeed ? currentItem.measureSpeed : detailState.baseSpeed;
+                changeSpeed(currentSpeed)
               }}
             />
           </div>

+ 1 - 0
src/pages/detail/tick-popup/index.tsx

@@ -45,6 +45,7 @@ export default defineComponent({
           display: 'flex',
           background: 'transparent',
         }}
+        teleport="body"
       >
         <Tick
           dots={(runtime as any)?.osmd?.numerator || getDuration((runtime as any).osmd).numerator || 0}

+ 6 - 6
src/subpages/colexiu/buttons/evaluating.tsx

@@ -322,7 +322,7 @@ export const formatPitch = (num?: number): number => {
 let starTime = 0
 const formatTimes = () => {
   // const rate = runtime.speed / detailState.baseSpeed //1
-  const rate = runtime.basePlayRate; // 播放倍率
+  const rate = runtime.basePlayRate * runtime.originAudioPlayRate; // 播放倍率
   console.log('评测倍率123',rate)
   actualBeatLength = Math.round(detailState.times[0].fixtime * 1000 / rate)
   const difftime = detailState.times?.[0]?.difftime || 0
@@ -389,7 +389,7 @@ const formatTimes = () => {
     const item = times[index]
     const note = getNoteByMeasuresSlursStart(item)
     // const rate = runtime.speed / detailState.baseSpeed //1
-    const rate = runtime.basePlayRate; // 播放倍率
+    const rate = runtime.basePlayRate * runtime.originAudioPlayRate; // 播放倍率
     const start = difftime + (item.sourceRelativeTime || item.relativeTime) - starTime
     const end = difftime + (item.sourceRelaEndtime || item.relaEndtime) - starTime
     // console.log(start, end, starTime)
@@ -459,7 +459,7 @@ const connect = async () => {
   const search = useOriginSearch()
   connentLoading.value = true
   const behaviorId = sessionStorage.getItem('behaviorId') || search.behaviorId || initBehaviorId
-  const rate = runtime.speed / detailState.baseSpeed //1
+  const rate = runtime.basePlayRate * runtime.originAudioPlayRate; // 播放倍率
   calculateInfo = formatTimes()
   detailState.firstNoteTime = calculateInfo.firstNoteTime;
   const content = {
@@ -483,7 +483,7 @@ const connect = async () => {
     // beatLength: Math.round((RuntimeUtils.getFixTime(detailState.times[0].beatSpeed) * 1000) / rate),
     beatLength: actualBeatLength,
     evaluationCriteria: getEvaluationCriteria(),
-    speedRate: parseFloat(runtime.basePlayRate.toFixed(2)), // 播放倍率
+    speedRate: parseFloat(rate.toFixed(2)), // 播放倍率
   }
   // console.log("🚀 ~ content:", content, rate)
   const clientType = useClientType()
@@ -720,14 +720,14 @@ const evaluatStart = () => {
     RuntimeUtils.setCaptureMode()
   }
   console.log('开始录音', new Date().getTime())
-  
+  const rate = runtime.basePlayRate * runtime.originAudioPlayRate; // 播放倍率
   postMessage(
     {
       api: 'startRecording',
       content: {
         accompanimentState: SettingState.eva.mute ? 1 : 0,
         firstNoteTime: calculateInfo.firstNoteTime || 0,
-        speedRate: parseFloat(runtime.basePlayRate.toFixed(2)), // 播放倍率
+        speedRate: parseFloat(rate.toFixed(2)), // 播放倍率
       }
     },
     () => {

+ 1 - 0
src/subpages/colexiu/buttons/index.tsx

@@ -110,6 +110,7 @@ export const onChangeModelType = (type: IModelType) => {
   }
   if (type === 'evaluation') {
     // RuntimeUtils.changeSpeed(detailState.activeDetail?.originalSpeed, false)
+    RuntimeUtils.resetBaseRate();
     // 评测模式
     runtime.evaluatingStatus = true
     modelType.value = type

+ 2 - 1
src/subpages/colexiu/popups/evaluating/content.tsx

@@ -144,8 +144,9 @@ export default defineComponent({
     // 播放倍率不等于1,或者是选段评测,APP暂时不支持保存演奏,需要给出提示
     const noSaveTips = computed(() => {
       let tipContent = '';
+      const rate = runtime.basePlayRate * runtime.originAudioPlayRate; // 播放倍率
       if (isUnitTest || detailState.section.length === 2 || detailState.activeDetail.isAppPlay || runtime.basePlayRate != 1 || !runtime.songs.background) {
-        tipContent = isUnitTest ? '单元测验暂不支持保存作品噢~' : (!runtime.songs.background || detailState.activeDetail.isAppPlay) ? '该曲目暂不支持保存作品噢~' : detailState.section.length === 2 ? '选段后暂不支持保存作品噢~' : runtime.basePlayRate != 1 ? '调速后暂不支持保存作品噢~' : '';
+        tipContent = isUnitTest ? '单元测验暂不支持保存作品噢~' : (!runtime.songs.background || detailState.activeDetail.isAppPlay) ? '该曲目暂不支持保存作品噢~' : detailState.section.length === 2 ? '选段后暂不支持保存作品噢~' : rate != 1 ? '调速后暂不支持保存作品噢~' : '';
       }
       return tipContent
     })

+ 2 - 1
src/subpages/colexiu/popups/evaluating/index.tsx

@@ -99,12 +99,13 @@ export default defineComponent({
         confirmShow.value = true
       } else {
         if (props.data?.recordIdStr) {
+          const rate = runtime.basePlayRate * runtime.originAudioPlayRate; // 播放倍率
           // 上传云端
           api_openAdjustRecording({
             recordId: String(props.data?.recordIdStr),
             title: detailState.activeDetail?.musicSheetName || "曲谱演奏",
             coverImg: detailState.activeDetail?.titleImg || '',
-            speedRate: parseFloat(runtime.basePlayRate.toFixed(2)), // 播放倍率
+            speedRate: parseFloat(rate.toFixed(2)), // 播放倍率
             // firstNoteTime: detailState.firstNoteTime,
           });
         }

+ 22 - 0
src/subpages/colexiu/popups/follow/index.tsx

@@ -106,6 +106,7 @@ const getDefaultIndex = () => {
 
 // 开始
 const handleStart = () => {
+  checking = false;
   onClear()
   data.start = true
   openToggleRecord(true)
@@ -126,6 +127,26 @@ const handleEnd = () => {
   getNoteIndex()
 }
 
+/**
+ * 2024.7.9 新增自动结束跟练模式功能
+ * 如果跟练模式,唱完了最后一个有频率的音符,需要自动结束掉跟练模式
+ * 需要判断当前音符的后面是否都是休止音符(休止音符的频率都是-1),或者是否是最后一个音符了
+ */
+const autoEndFollow = () => {
+	if (data.index >= detailState.times.length) {
+		handleEnd()
+		return
+	}
+	let nextIndex = data.index + 1;
+	const rightTimes = detailState.times.slice(data.index,detailState.times.length)
+	// 后面的音符是否都是休止音符
+	const isAllRest = !rightTimes.some((item: any) => item.frequency > 1);
+	if (isAllRest && detailState.times[data.index].frequency < 1) {
+		handleEnd()
+		return
+	}
+}
+
 // 下一个
 const next = () => {
   if (state.osmd.product) {
@@ -134,6 +155,7 @@ const next = () => {
     state.osmd.cursor.next()
   }
   refreshView()
+  autoEndFollow()
 }
 
 // 获取当前音符