skyblued před 2 roky
rodič
revize
c5d438bca1

+ 286 - 0
src/pages/detail/calcSpeed.ts

@@ -0,0 +1,286 @@
+import { onlyVisible } from './helpers'
+import { OpenSheetMusicDisplay, SourceMeasure } from '/osmd-extended/src'
+
+export const noteDuration = {
+  '1/2': 2,
+  w: 1,
+  h: 0.5,
+  q: 0.25,
+  '8': 0.125,
+  '16': 0.0625,
+  '32': 0.03125,
+  '64': 0.015625,
+  '128': 0.0078125,
+}
+
+export type GradualChange = {
+  resetXmlNoteIndex: number
+  startXmlNoteIndex: number
+  endXmlNoteIndex: number
+  startWord: string
+  startMeasureListIndex: number
+  endMeasureListIndex: number
+  resetMeasureListIndex: number
+}
+
+export const speedInfo: { [key in string]: number } = {
+  'rall.': 1.333333333,
+  'poco rit.': 1.333333333,
+  'rit.': 1.333333333,
+  'molto rit.': 1.333333333,
+  'molto rall': 1.333333333,
+  'molto': 1.333333333,
+  lentando: 1.333333333,
+  allargando: 1.333333333,
+  morendo: 1.333333333,
+  'accel.': 0.8,
+  calando: 2,
+  'poco accel.': 0.8,
+  'gradually slowing': 1.333333333,
+  'slowing': 1.333333333,
+  'slow': 1.333333333,
+  'slowly': 1.333333333,
+  faster: 1.333333333,
+}
+
+/**
+ * 计算渐变速度
+ */
+export const calcGradual = () => {}
+
+/**
+ * 2022年9月14日版本 计算渐变速度,此方法不兼容之前的选择范围。
+ */
+export const calcGradual2 = () => {}
+
+/**
+ * 获取指定元素下一个Note元素
+ * @param ele 指定元素
+ * @param selectors 选择器
+ */
+const getNextNote = (ele: Element, selectors: string) => {
+  let index = 0
+  const parentEle = ele.closest(selectors)
+  let pointer = parentEle
+  const measure = parentEle?.closest('measure')
+  let siblingNote: Element | null | undefined = null
+  // 查找到相邻的第一个note元素
+  while (!siblingNote && index < (measure?.childNodes.length || 50)) {
+    index++
+    if (pointer?.nextElementSibling?.tagName === 'note') {
+      siblingNote = pointer?.nextElementSibling
+    }
+    pointer = pointer?.nextElementSibling!
+  }
+  return siblingNote
+}
+
+export type GradualElement = {
+  ele: Element
+  index: number
+  noteInMeasureIndex: number
+  textContent: string
+  measureIndex: number
+  type: 'words' | 'metronome'
+  allDuration: number
+  leftDuration: number
+}
+
+export type GradualNote = GradualItem[]
+
+export type GradualItem = {
+  start: number
+  measureIndex: number
+  noteInMeasureIndex: number
+  allDuration: number
+  leftDuration: number
+  type: string
+  closedMeasureIndex: number
+}
+
+// export type GradualItem = {
+//   start: number
+//   startMeasureIndex: number
+//   startNoteInMeasureIndex: number
+//   allDuration: number
+//   leftDuration: number
+//   endNoteInMeasureIndex?: number
+//   endMeasureIndex?: number
+//   end?: number
+// }
+
+/**
+ * 按照xml进行减慢速度的计算
+ * @param xml 始终按照第一分谱进行减慢速度的计算
+ */
+export const getGradualLengthByXml = (xml: string) => {
+  const firstPartXml = onlyVisible(xml, 0)
+  const xmlParse = new DOMParser().parseFromString(firstPartXml, 'text/xml')
+  const measures = Array.from(xmlParse.querySelectorAll('measure'))
+  const notes = Array.from(xmlParse.querySelectorAll('note'))
+  const words = Array.from(xmlParse.querySelectorAll('words'))
+  const metronomes = Array.from(xmlParse.querySelectorAll('metronome'))
+
+  const eles: GradualElement[] = []
+
+  for (const ele of [...words, ...metronomes]) {
+    const note = getNextNote(ele, 'direction')
+    // console.log(ele, note)
+    if (note) {
+      const measure = note?.closest('measure')!
+      const measureNotes = Array.from(measure.querySelectorAll('note'))
+
+      const noteInMeasureIndex = Array.from(measure.childNodes)
+        .filter((item) => item.nodeName === 'note')
+        .findIndex((item) => item === note)
+
+      let allDuration = 0
+      let leftDuration = 0
+      for (let i = 0; i < measureNotes.length; i++) {
+        const n = measureNotes[i]
+        const duration = +(n.querySelector('duration')?.textContent || '0')
+        allDuration += duration
+        if (i < noteInMeasureIndex) {
+          leftDuration = allDuration
+        }
+      }
+      eles.push({
+        ele,
+        index: notes.indexOf(note!),
+        noteInMeasureIndex,
+        textContent: ele.textContent!,
+        measureIndex: measures.indexOf(measure!),
+        type: ele.tagName as GradualElement['type'],
+        allDuration,
+        leftDuration,
+      })
+    }
+  }
+
+  // 结尾处手动插入一个音符节点
+  eles.push({
+    ele: notes[notes.length - 1],
+    index: notes.length,
+    noteInMeasureIndex: 0,
+    textContent: '',
+    type: 'metronome',
+    allDuration: 1,
+    leftDuration: 1,
+    measureIndex: measures.length,
+  })
+
+  const gradualNotes: GradualNote[] = []
+  eles.sort((a, b) => a.index - b.index)
+  const keys = Object.keys(speedInfo).map(w => w.toLocaleLowerCase())
+  for (const ele of eles) {
+    // 是否是同时也是关闭标签
+  let isLastNoteAndNotClosed = false
+    let closed = 0
+    const textContent = ele.textContent?.toLocaleLowerCase().trim()
+    if (ele === eles[eles.length - 1]) {
+      if (gradualNotes[gradualNotes.length - 1]?.length === 1) {
+        isLastNoteAndNotClosed = true
+      }
+    }
+    const isKeyWork = keys.find(k => {
+      const ks = k.split(' ')
+      return textContent && ks.includes(textContent)
+    })
+    if (
+      ele.type === "metronome" ||
+      (ele.type === "words" && (textContent.startsWith("a tempo") || isKeyWork) || isLastNoteAndNotClosed)
+    ) {
+      const indexOf = gradualNotes.findIndex((item) => item.length === 1)
+      if (indexOf > -1 && ele.index > gradualNotes[indexOf]?.[0].start) {
+        closed = -1
+        gradualNotes[indexOf][1] = {
+          start: ele.index,
+          measureIndex: ele.measureIndex,
+          closedMeasureIndex: ele.measureIndex,
+          noteInMeasureIndex: ele.noteInMeasureIndex,
+          allDuration: ele.allDuration,
+          leftDuration: ele.leftDuration,
+          type: textContent,
+        }
+      }
+    }
+    if (ele.type === 'words' && isKeyWork) {
+      gradualNotes.push([
+        {
+          start: ele.index,
+          measureIndex: ele.measureIndex,
+          closedMeasureIndex: ele.measureIndex + closed,
+          noteInMeasureIndex: ele.noteInMeasureIndex,
+          allDuration: ele.allDuration,
+          leftDuration: ele.leftDuration,
+          type: textContent,
+        },
+      ])
+    }
+  }
+  return gradualNotes
+}
+
+export const getGradualLength = (
+  gradualChange: GradualChange,
+  speed: number,
+  osdm: OpenSheetMusicDisplay
+) => {
+  const {
+    startMeasureListIndex,
+    endMeasureListIndex,
+    endXmlNoteIndex,
+    startWord,
+  } = gradualChange
+  const measures: SourceMeasure[] = []
+  for (
+    let index = startMeasureListIndex;
+    index <= endMeasureListIndex;
+    index++
+  ) {
+    const measure = osdm.Sheet.SourceMeasures[index]
+    measures.push(measure)
+  }
+  const allNoteDurations: number[] = []
+  for (const measure of measures) {
+    if (allNoteDurations.length >= endXmlNoteIndex) {
+      break
+    }
+    // @ts-ignore
+    measure.VerticalMeasureList[0]?.vfVoices['1']?.tickables?.forEach((item) =>
+      allNoteDurations.push(
+        noteDuration[item.duration as keyof typeof noteDuration]
+      )
+    )
+  }
+  const minDuration = Math.min(...allNoteDurations)
+  const parts = allNoteDurations.map((item) => item / minDuration)
+  const allParts = parts.reduce((total, val) => val + total, 0)
+  // const startMeasure = osdm.Sheet.SourceMeasures[startMeasureListIndex]
+  // const endMeasure = osdm.Sheet.SourceMeasures[endMeasureListIndex]
+  let surplusSpeed = speed / speedInfo[startWord?.toLocaleLowerCase()] || 1
+  const diffSpeed = speed - surplusSpeed
+  let useSpeed = 0
+  const speeds: number[] = parts.map((item) => {
+    const s = ((diffSpeed - useSpeed) * item) / allParts
+    return s
+  })
+  // 120 111.9 104.4 96.9
+  // 8.1 7.5 7.2 6.9
+  // 0.6 0.3 0.3
+  const lingerSpeed: number[] = []
+  for (let index = 0; index < speeds.length; index++) {
+    const s = speeds[index]
+    let beforeSpeed = 0
+    let afterSpeed = 0
+    for (let j = 0; j < index; j++) {
+      beforeSpeed += speeds[j]
+    }
+    afterSpeed += beforeSpeed
+    afterSpeed += s
+
+    lingerSpeed.push((afterSpeed + beforeSpeed) / 2)
+  }
+  // console.log(lingerSpeed, speeds[0], speeds, parts, allParts)
+  return lingerSpeed
+}

+ 111 - 11
src/pages/detail/helpers.ts

@@ -12,6 +12,7 @@ import {
   GRADIENT_SPEED_RESET_TAG,
   StringUtil,
 } from '/osmd-extended/src'
+import dayjs from 'dayjs'
 const browserInfo = browser()
 
 const getLinkId = (): string => {
@@ -145,6 +146,17 @@ export const createSpeedInfo = (gradualChange: GradualChange | undefined, speed:
   }
   return
 }
+const tranTime = (str: string = '') => {
+  let result = str
+  const splits = str.split(':')
+  if (splits.length === 1) {
+    result = `00:${splits[0]}:00`
+  } else if (splits.length === 2) {
+    result = `00:${splits[0]}:${splits[1]}`
+  }
+  // console.log(`1970-01-01 00:${result}0`)
+  return `1970-01-01 00:${result}0`
+}
 export const getAllNodes = (osmd: any) => {
   const detailId = getLinkId()
   let fixtime = browserInfo.huawei ? 0.08 : 0 //getFixTime()
@@ -175,6 +187,9 @@ export const getAllNodes = (osmd: any) => {
     }
     return realKey
   }
+  if (state.gradualTimes) {
+    console.log('合奏速度', state.gradual, state.gradualTimes)
+  }
   if (osmd?.cursor) {
     try {
       osmd.cursor.reset()
@@ -189,6 +204,7 @@ export const getAllNodes = (osmd: any) => {
     /** 弱起时间 */
     let difftime = 0
     let beatUnit = 'quarter'
+    let useGradualTime = 0
     let gradualSpeed
     let gradualChange: GradualChange | undefined
     let gradualChangeIndex = 0
@@ -212,8 +228,6 @@ export const getAllNodes = (osmd: any) => {
         cursorBox.y = cursorImg.offsetTop
         cursorBox.w = cursorImg.offsetWidth
         cursorBox.h = cursorImg.offsetHeight
-        // console.log(cursorImg.offsetLeft, cursorImg.offsetTop, cursorImg.offsetWidth, cursorImg.offsetHeight)
-        // console.log(cursorImg.getAttribute('style'))
       }
       const voiceEntries = iterator.currentVoiceEntries?.[0] ? [iterator.currentVoiceEntries?.[0]] : []
       const voiceEntries2 = iterator.currentVoiceEntries?.[1]
@@ -266,8 +280,20 @@ export const getAllNodes = (osmd: any) => {
           let { wholeValue, numerator, denominator, realValue: noteRealValue } = note.length
 
           let relativeTime = usetime //realValue * 4 * (60 / measureSpeed)
-          // 速度不能为0
-          // 此处的速度应该是按照设置的速度而不是校准后的速度,否则mp3速度不对
+          /**
+           * 速度不能为0, 此处的速度应该是按照设置的速度而不是校准后的速度,否则mp3速度不对
+           */
+          let beatSpeed =
+            (state.isSpecialBookCategory
+              ? getTimeByBeatUnit(beatUnit, measureSpeed, iterator.currentMeasure.activeTimeSignature.Denominator)
+              : baseSpeed) || 1
+          let speed = (state.isSpecialBookCategory ? measureSpeed : baseSpeed) || 1
+          // console.log('曲谱设置的速度', { base: getTimeByBeatUnit(beatUnit, measureSpeed, iterator.currentMeasure.activeTimeSignature.Denominator), beatSpeed, speed})
+          gradualChange = iterator.currentMeasure.speedInfo || gradualChange
+          gradualSpeed = osmd.sheet.soundTempos?.get(note.sourceMeasure.measureListIndex) || gradualSpeed
+          if (!gradualSpeed || gradualSpeed.length < 2) {
+            gradualSpeed = createSpeedInfo(gradualChange, speed)
+          }
           /**
            * 渐变速度逻辑如下:
            * 1. 获取渐变关键词,记录开始区间、结束区间、渐变整体结束;
@@ -275,12 +301,82 @@ export const getAllNodes = (osmd: any) => {
            * 3. 按照比例计算下一个音符的速度;
            * 4. 合奏曲目这里需要处理一下,因为音符位置可能不太相同,理想的情况是每个分谱指定结束时间.
            */
-          let beatSpeed =
+          let gradualLength = 0
+          const measureListIndex = iterator.currentMeasure.measureListIndex
+          if (state.gradualTimes && Object.keys(state.gradualTimes).length > 0) {
+            const withInRangeNote = state.gradual.find((item, index) => {
+              const nextItem: any = state.gradual[index + 1]
+              return (
+                item[0].measureIndex <= measureListIndex &&
+                item[1]?.measureIndex! >= measureListIndex &&
+                (!nextItem || nextItem?.[0].measureIndex !== measureListIndex)
+              )
+            })
+            if (!withInRangeNote) {
+              useGradualTime = 0
+            }
+            const [first, last] = withInRangeNote || []
+            if (first && last) {
+              // 小节数量
+              const continuous = last.measureIndex - first.measureIndex
+              // 开始小节内
+              const inTheFirstMeasure = first.closedMeasureIndex == measureListIndex && si >= first.noteInMeasureIndex
+              // 结束小节内
+              const inTheLastMeasure = last.closedMeasureIndex === measureListIndex && si < last.noteInMeasureIndex
+              // 范围内小节
+              const inFiestOrLastMeasure =
+                first.closedMeasureIndex !== measureListIndex && last.closedMeasureIndex !== measureListIndex
+              if (inTheFirstMeasure || inTheLastMeasure || inFiestOrLastMeasure) {
+                const startTime = state.gradualTimes[first.measureIndex]
+                const endTime = state.gradualTimes[last.measureIndex]
+                if (startTime && endTime) {
+                  const times =
+                    continuous - first.leftDuration / first.allDuration + last.leftDuration / last.allDuration
+                  const diff = dayjs(tranTime(endTime)).diff(dayjs(tranTime(startTime)), 'millisecond')
+                  gradualLength = ((noteRealValue / vRealValue / times) * diff) / 1000
+                  useGradualTime += gradualLength
+                }
+              }
+            }
+          } else if (
+            gradualChange &&
+            gradualSpeed &&
+            (gradualChange.startXmlNoteIndex === si || gradualChangeIndex > 0)
+          ) {
+            const startSpeed = gradualSpeed[0] - (gradualSpeed[1] - gradualSpeed[0])
+            const { resetXmlNoteIndex, endXmlNoteIndex } = gradualChange
+            const noteDiff = endXmlNoteIndex
+            let stepSpeed = (gradualSpeed[gradualSpeed.length - 1] - startSpeed) / noteDiff
+            stepSpeed = note.DotsXml ? stepSpeed / 1.5 : stepSpeed
+            if (gradualChangeIndex < noteDiff) {
+              const tempSpeed = Math.ceil(speed + stepSpeed * gradualChangeIndex)
+              let tmpSpeed = getTimeByBeatUnit(
+                beatUnit,
+                tempSpeed,
+                iterator.currentMeasure.activeTimeSignature.Denominator
+              )
+              const maxLength = (wholeValue + numerator / denominator) * vDenominator * (60 / tmpSpeed)
+              speed += Math.ceil(stepSpeed * (gradualChangeIndex + 1))
+              tmpSpeed = getTimeByBeatUnit(beatUnit, speed, iterator.currentMeasure.activeTimeSignature.Denominator)
+              const minLength = (wholeValue + numerator / denominator) * vDenominator * (60 / tmpSpeed)
+              gradualLength = (maxLength + minLength) / 2
+            } else if (resetXmlNoteIndex > gradualChangeIndex) {
+              speed = allNotes[i - 1]?.speed
+            }
+            beatSpeed =
             (state.isSpecialBookCategory
-              ? getTimeByBeatUnit(beatUnit, measureSpeed, iterator.currentMeasure.activeTimeSignature.Denominator)
+              ? getTimeByBeatUnit(beatUnit, speed, iterator.currentMeasure.activeTimeSignature.Denominator)
               : baseSpeed) || 1
-          let speed = (state.isSpecialBookCategory ? measureSpeed : baseSpeed) || 1
-          // console.log('曲谱设置的速度', { isTeshu:state.isSpecialBookCategory, beatSpeed, speed})
+              const isEnd = !(gradualChangeIndex < noteDiff) && !(resetXmlNoteIndex > gradualChangeIndex)
+            gradualChangeIndex++
+            // console.log(gradualChangeIndex)
+            if (isEnd) {
+              gradualChangeIndex = 0
+              gradualChange = undefined
+              gradualSpeed = undefined
+              stepSpeeds = []
+            }
+          }
           if (i === 0) {
             fixtime += getFixTime(beatSpeed)
           }
@@ -291,7 +387,9 @@ export const getAllNodes = (osmd: any) => {
           // vDenominator *
           // (60 / beatSpeed)
           //管乐迷计算时值方法
-          let noteLength = Math.min(vRealValue, noteRealValue) * formatBeatUnit(beatUnit) * (60 / beatSpeed)
+          let noteLength = gradualLength
+            ? gradualLength
+            : Math.min(vRealValue, noteRealValue) * formatBeatUnit(beatUnit) * (60 / beatSpeed)
           const measureLength = vRealValue * vDenominator * (60 / beatSpeed)
           // 单独处理个别的声部
           if (['Piano'].includes(state.activeDetail?.code)) {
@@ -317,6 +415,7 @@ export const getAllNodes = (osmd: any) => {
           }
           // 处理附点时长不正确问题
           if (note.DotsXml && note.tuplet) {
+            console.log('处理附点时长不正确问题')
             noteLength = noteLength * 1.5
           }
           // 后倚音通过跳过的方式实现
@@ -657,7 +756,8 @@ export const getIndex = (times: any[], currentTime: Number) => {
 }
 
 export const getSlursNote = (_note: any, pos?: 'start' | 'end') => {
-  const note: any = state.times.find((n: any) => n.NoteToGraphicalNoteObjectId == _note.NoteToGraphicalNoteObjectId) || {}
+  const note: any =
+    state.times.find((n: any) => n.NoteToGraphicalNoteObjectId == _note.NoteToGraphicalNoteObjectId) || {}
   let itemNote = pos === 'end' ? note.noteElement.slurs[0]?.endNote : note.noteElement.slurs[0]?.startNote
   // console.log("🚀 ~ itemNote", itemNote, note)
   if (!itemNote) return undefined
@@ -809,7 +909,7 @@ export const getDuration = (osmd: any): any => {
         return {
           ...formatDuration(activeTimeSignature, duration),
           tempoInBPM,
-          beatUnit
+          beatUnit,
         }
       }
     }

+ 10 - 1
src/pages/detail/state.ts

@@ -1,5 +1,6 @@
 import { Toast } from 'vant'
 import { reactive, watchEffect } from 'vue'
+import { GradualNote } from './calcSpeed'
 import { IDifficulty } from './setting-state'
 
 type IRenderType = 'native' | 'cache'
@@ -66,7 +67,12 @@ const state = reactive({
   /** 渲染比例 */
   zoom: 1,
   /** 渲染模式*/
-  renderType: 'native' as IRenderType
+  renderType: 'native' as IRenderType,
+  /** 渐变速度信息 */
+  gradual: [] as GradualNote[],
+  /** 渐变速度版本 */
+  /** 渐变时间信息 */
+  gradualTimes: null as GradualTimes
 })
 
 let toastItem: any = null
@@ -95,3 +101,6 @@ watchEffect(() => {
 })
 
 export default state
+export type GradualTimes = null | {
+  [key: string]: string
+}

+ 3 - 3
src/subpages/colexiu/index.tsx

@@ -171,13 +171,13 @@ export default defineComponent({
       //@ts-ignore
       const saveSpeed = (store.get('speeds') || {})[search.id]
       const bpm = (osmd as any).bpm || osmd.Sheet.userStartTempoInBPM
-
+      
       detailState.activeSpeed = saveSpeed || detail.value.playSpeed || bpm || 100
-      detailState.baseSpeed = saveSpeed || detail.value.playSpeed || bpm || 100
+      detailState.baseSpeed = detail.value.playSpeed || bpm || 100
       detailState.code = detail.value?.code || ''
       detailState.activeDetail.originalSpeed = detailState.baseSpeed
       // 设置成全部是特殊曲谱
-      // detailState.isSpecialBookCategory = true
+      detailState.isSpecialBookCategory = true
       if (detailState.renderType === 'native') {
         detailState.times = getAllNodes(osmd)
       }

+ 22 - 5
src/subpages/colexiu/uses/use-app.ts

@@ -4,7 +4,7 @@ import request from '/src/helpers/request'
 import originRequest from 'umi-request'
 import store from 'store'
 import runtime, * as RuntimeUtils from '/src/pages/detail/runtime'
-import detailState from '/src/pages/detail/state'
+import detailState, { GradualTimes } from '/src/pages/detail/state'
 import SettingState from '/src/pages/detail/setting-state'
 import { listenerMessage, postMessage } from '/src/helpers/native-message'
 import audiosInstance from '/src/helpers/multiple-audio'
@@ -13,6 +13,8 @@ import { MusicSheelDetail, ShaeetStatusType } from '../index.d'
 import { browser, getRequestHostname } from '/src/helpers/utils'
 import formatId, { getSubjectIdCode } from '../fingering/format-id'
 import { evaluatStopPlay } from '../buttons/evaluating'
+import state from '/src/pages/detail/state'
+import { getGradualLengthByXml } from '/src/pages/detail/calcSpeed'
 
 const search = useOriginSearch()
 const skpList = ['Ukulele']
@@ -24,6 +26,7 @@ const skpList = ['Ukulele']
  * @returns Ref<string>
  */
 export const useXml = async (url: string, detail: MusicSheelDetail) => {
+  const partIndex = Number(search['part-index']) || 0
   let score = ref<string>('')
   try {
     const xml = await originRequest(url)
@@ -34,9 +37,9 @@ export const useXml = async (url: string, detail: MusicSheelDetail) => {
       score.value = formatXML(parseXmlInfo.parsedXML, {
         title: detail.musicSheetName,
       })
-      const partIndex = Number(search['part-index']) || 0
       score.value = onlyVisible(score.value, partIndex)
     }
+    state.gradual = getGradualLengthByXml(xml)
   } catch (error) {}
   return score
 }
@@ -51,9 +54,9 @@ export const useMp3s = async (detail: MusicSheelDetail) => {
   const activebg = detail.background?.[partIndex]
 
   // 伴奏
-  const backgroundSong = encodeURI(detail.audioFileUrl || detail.metronomeUrl || detail.url || '')
+  const backgroundSong = encodeURI(detail.metronomeUrl || detail.audioFileUrl || detail.url || '')
   // 原音
-  const musicSong = encodeURI(activebg?.audioFileUrl || activebg?.metronomeUrl || '')
+  const musicSong = encodeURI(activebg?.metronomeUrl || activebg?.audioFileUrl || '')
   // 兼容未修改之前
   runtime.songs = {
     background: backgroundSong ? backgroundSong + '?t=background' : '',
@@ -160,6 +163,20 @@ export const useDetail = (id: number | string): [Ref<ShaeetStatusType>, Ref<Musi
       detailState.subjectId = (res.data.musicSubject || '').split(',')[0] || 0
       ;(window as any).DYSubjectId = formatId(data.value.code as any)
       status.value = 'success'
+
+      // 额外配置
+      let extConfigJson = {
+        gradualTimes: {},
+      }
+      try {
+        if (data.value?.extConfigJson) {
+          extConfigJson = {
+            ...extConfigJson,
+            ...JSON.parse(data.value.extConfigJson),
+          }
+        }
+      } catch (error) {}
+      state.gradualTimes = extConfigJson.gradualTimes as GradualTimes
     })
     .catch(() => (status.value = 'error'))
 
@@ -186,7 +203,7 @@ export const useSuspendPlay = () => {
         //     detailState.isPauseRecording = true
         //   }
         // )
-        evaluatStopPlay(false)
+        evaluatStopPlay()
       }
     }
   })