| 
					
				 | 
			
			
				@@ -221,6 +221,27 @@ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             bucket_name="cloud-coach" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         /> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       </el-form-item> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      <div v-if="gradual && gradual.length"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        <el-alert :closable="false" style="margin-bottom: 20px;">识别到共{{gradual.length}}处渐变速度,请输入对应小节时间信息</el-alert> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        <div v-for="item in gradual"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          <el-form-item 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            :label="item[0].measureIndex + ' 小节'" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            :rules="[{required: true, message: '请输入合奏曲目时间'}]" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            :prop="`graduals.${item[0].measureIndex}`" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          > 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            <el-input placeholder="00:00:000" v-model="form.graduals[item[0].measureIndex]"></el-input> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          </el-form-item> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          <el-form-item 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            :label="item[1].measureIndex + ' 小节'" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            :rules="[{required: true, message: '请输入合奏曲目时间'}]" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            :prop="`graduals.${item[1].measureIndex}`" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          > 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            <el-input placeholder="00:00:000" v-model="form.graduals[item[1].measureIndex]"></el-input> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          </el-form-item> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        </div> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      </div> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       <div 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         class="files" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         v-for="(song, index) in form.sysMusicScoreAccompaniments" 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -398,12 +419,14 @@ export default { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   props: ["detail", "type"], 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   data() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     return { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      gradual: null, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       xmlFirstSpeed: '', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       partListNames: [], 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       tree: [], 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       extConfigJson: {}, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       memberRankList: [], // 会员列表 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       form: { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        graduals: {}, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         rankIdType: 0, // 收费会员类型 默认免费 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         repeatedBeats: 0, // 重复节拍 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         sysMusicScore: { 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -453,6 +476,7 @@ export default { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         this.extConfigJson = {...initailExtConfigJson} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       this.form.repeatedBeats = this.extConfigJson.repeatedBeats; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      this.form.gradual = this.extConfigJson.gradualTimes || {}; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       this.$set(this.form, "sysMusicScore", { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         isOpenMetronome:Number(this.detail.isOpenMetronome), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         name: this.detail.name, 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -475,6 +499,7 @@ export default { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         this.form.rankIdType = 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       const xmlres = await axios(this.detail.xmlUrl) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      this.gradual = getGradualLengthByXml(xmlres.data) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       this.partListNames = this.getPartListNames(xmlres.data) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       this.FeatchDetailList(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     } else { 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -496,6 +521,7 @@ export default { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       const xmlRead = new FileReader() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       xmlRead.onload = res => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         this.partListNames = this.getPartListNames(res.target.result) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        this.partListNames = this.getPartListNames(res.target.result) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         for (let j = 0; j < this.form.sysMusicScoreAccompaniments.length; j++) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				           this.form.sysMusicScoreAccompaniments[j].track =  this.partListNames[j] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				           if (!this.form.sysMusicScoreAccompaniments[j].speed) { 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -634,6 +660,7 @@ export default { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 ...this.form.sysMusicScore, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 extConfigJson: JSON.stringify({ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                   repeatedBeats: this.form.repeatedBeats, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                  gradualTimes: this.form.graduals, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 }), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 type: "COMMON", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 showFlag: 0, 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -650,6 +677,7 @@ export default { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 ...this.form.sysMusicScore, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 extConfigJson: JSON.stringify({ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                   repeatedBeats: this.form.repeatedBeats, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                  gradualTimes: this.form.graduals, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 }), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 type: "COMMON", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 id: this.detail.id, 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -668,6 +696,211 @@ export default { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+/** 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * 获取指定元素下一个Note元素 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @param ele 指定元素 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @param selectors 选择器 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ const getNextNote = (ele, selectors) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  let index = 0 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  const parentEle = ele.closest(selectors) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  let pointer = parentEle 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  const measure = parentEle?.closest('measure') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  let siblingNote = null 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  // 查找到相邻的第一个note元素 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  while (!siblingNote && index < (measure?.childNodes.length || 50)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    index++ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (pointer?.nextElementSibling?.tagName === 'note') { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      siblingNote = pointer?.nextElementSibling 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    pointer = pointer?.nextElementSibling 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  return siblingNote 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+export const onlyVisible = (xml, partIndex) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (!xml) return '' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  const xmlParse = new DOMParser().parseFromString(xml, 'text/xml') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  const partList = xmlParse.getElementsByTagName('part-list')?.[0]?.getElementsByTagName('score-part') || [] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  // const partListNames = Array.from(partList).map(item => item.getElementsByTagName('part-name')?.[0].textContent || '') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  const parts = xmlParse.getElementsByTagName('part') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  // const firstTimeInfo = parts[0]?.getElementsByTagName('metronome')[0]?.parentElement?.parentElement?.cloneNode(true) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  // const firstMeasures = [...Array.from(parts[0]?.getElementsByTagName('measure') || [])] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  // const metronomes = [...Array.from(parts[0]?.getElementsByTagName('metronome') || [])] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  // const words = [...Array.from(parts[0]?.getElementsByTagName('words') || [])] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  // const codas = [...Array.from(parts[0]?.getElementsByTagName('coda') || [])] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  // const rehearsals = [...Array.from(parts[0]?.getElementsByTagName('rehearsal') || [])] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  const visiblePartInfo = partList[partIndex] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  // console.log(visiblePartInfo, partIndex) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  // state.partListNames = partListNames 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (visiblePartInfo) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    const id = visiblePartInfo.getAttribute('id') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    Array.from(parts).forEach(part => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      if (part && part.getAttribute('id') !== id) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        part.parentNode?.removeChild(part) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // 不等于第一行才添加避免重复添加 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // words.forEach(word => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        //   const text = word.textContent || '' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        //   if(isSpeedKeyword(text) && text) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        //     const wordContainer = word.parentElement?.parentElement?.parentElement 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        //     if (wordContainer && wordContainer.firstElementChild && wordContainer.firstElementChild !== word) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        //       const wordParent = word.parentElement?.parentElement 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        //       const fisrt = wordContainer.firstElementChild 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        //       wordContainer.insertBefore(wordParent, fisrt) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        //     } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        //   } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // }) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      // 最后一个小节的结束线元素不在最后 调整 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      if (part && part.getAttribute('id') === id) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        const barlines = part.getElementsByTagName('barline') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        const lastParent = barlines[barlines.length - 1]?.parentElement 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if (lastParent?.lastElementChild?.tagName !== 'barline') { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          const children = lastParent?.children || [] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          for (let el of children) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if (el.tagName === 'barline') { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              // 将结束线元素放到最后 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              lastParent?.appendChild(el) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              break 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    Array.from(partList).forEach(part => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      if (part && part.getAttribute('id') !== id) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        part.parentNode?.removeChild(part) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // 处理装饰音问题 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    const notes = xmlParse.getElementsByTagName('note') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    const getNextvNoteDuration = (i) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      let nextNote = notes[i + 1] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      // 可能存在多个装饰音问题,取下一个非装饰音时值 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      for (let index = i; index < notes.length; index++) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        const note = notes[index]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if (!note.getElementsByTagName('grace')?.length) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          nextNote = note 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          break 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      const nextNoteDuration = nextNote?.getElementsByTagName('duration')[0] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      return nextNoteDuration 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    Array.from(notes).forEach((note, i) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      const graces = note.getElementsByTagName('grace') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      if (graces && graces.length) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // if (i !== 0) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          note.appendChild(getNextvNoteDuration(i)?.cloneNode(true)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  // console.log(new XMLSerializer().serializeToString(xmlParse)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  return new XMLSerializer().serializeToString(xmlParse) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const speedInfo = { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  'rall.': 1.333333333, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  'poco rit.': 1.333333333, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  'rit.': 1.333333333, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  'molto rit.': 1.333333333, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  'molto rall': 1.333333333, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  lentando: 1.333333333, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  allargando: 1.333333333, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  morendo: 1.333333333, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  'accel.': 0.8, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  calando: 2, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  'poco accel.': 0.8, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+/** 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * 按照xml进行减慢速度的计算 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @param xml 始终按照第一分谱进行减慢速度的计算 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ export function getGradualLengthByXml (xml) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  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 = [] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  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, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        allDuration, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        leftDuration, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      }) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  const gradualNotes = [] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  eles.sort((a, b) => a.index - b.index) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  const keys = Object.keys(speedInfo).map(w => w.toLocaleLowerCase()) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  for (const ele of eles) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    const textContent = ele.textContent?.toLocaleLowerCase().trim() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (ele.type === 'words' && keys.includes(textContent)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      gradualNotes.push([ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          start: ele.index, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          measureIndex: ele.measureIndex, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          noteInMeasureIndex: ele.noteInMeasureIndex, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          allDuration: ele.allDuration, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          leftDuration: ele.leftDuration, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          type: textContent, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      ]) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if ( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      ele.type === 'metronome' || 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      (ele.type === 'words' && textContent === 'a tempo') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    ) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      const indexOf = gradualNotes.findIndex((item) => item.length === 1) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      if (indexOf > -1 && ele.index > gradualNotes[indexOf]?.[0].start) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        gradualNotes[indexOf][1] = { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          start: ele.index, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          measureIndex: ele.measureIndex, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          noteInMeasureIndex: ele.noteInMeasureIndex, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          allDuration: ele.allDuration, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          leftDuration: ele.leftDuration, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          type: textContent, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  return gradualNotes 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 </script> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 <style lang="less" scoped> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 .btns { 
			 |