Selaa lähdekoodia

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

TIANYONG 10 kuukautta sitten
vanhempi
commit
92e1463a5d

+ 6 - 2
src/page-instrument/view-detail/smoothAnimation/index.ts

@@ -28,7 +28,7 @@ type smoothAnimationType = {
    aveSpeed: number
 }
 
-const _numberOfSegments = 60 // 中间切割线的个数
+let _numberOfSegments = 56 // 中间切割线的个数
 const _canvasDomHeight = 60 // canvans 高度
 
 export const smoothAnimationState = {
@@ -70,6 +70,10 @@ export function initSmoothAnimation() {
    const batePos = getPointsPosByBatePos()
    smoothAnimationState.batePos = batePos
    const batePos1 = dataFilter([...batePos])
+   console.log(batePos1, "排序之后的数据")
+   // 这里性能优化,对于超级长的曲子,_numberOfSegments值 动态变化
+   const numberOfSegments = parseInt(16000 / batePos1.length + "")
+   _numberOfSegments = Math.max(18, Math.min(_numberOfSegments, numberOfSegments))
    const batePos2 = createSmoothCurvePoints(batePos1, _numberOfSegments)
    smoothAnimationState.pointsPos = batePos2
    // 初始化旋律线
@@ -402,7 +406,7 @@ function quantileScale(data: number[], minRange = 0, maxRange = _canvasDomHeight
 /**
  * 使用传入的曲线的顶点坐标创建平滑曲线的顶点。
  * @param  {Array}   points  曲线顶点坐标数组,
- * @param  {Int}     numberOfSegments 平滑曲线 2 个顶点间的线段数,默认为 20
+ * @param  {Int}     numberOfSegments 平滑曲线 2 个顶点间的线段数
  * @return {Array}   平滑曲线的顶点坐标数组
  */
 function createSmoothCurvePoints(points: pointsPosType, numSegments: number) {

+ 34 - 26
src/state.ts

@@ -1000,13 +1000,16 @@ export const gotoNext = (note: any, skipNote?: boolean) => {
   const num = note.i;
 
   if (state.activeNoteIndex === note.i) {
-    try {
-      setCursorPosition(note, state.osmd.cursor, 'init');
-    } catch (error) {
-      console.log(error);
-    }
+    /* 没有光标了  这里就算加上光标也要性能优化 */
+    // try {
+    //   setCursorPosition(note, state.osmd.cursor, 'init');
+    // } catch (error) {
+    //   console.log(error);
+    // }
     // 重置 或者切换演奏演唱的时候 可能出现 state.activeNoteIndex === note.i的情况 执行
-    fillWordColor();
+    if(state.playState === "paused"){
+      fillWordColor();
+    }
     if (state.isSingleLine && state.playState === "paused") {
       moveSvgDom(skipNote);
     }
@@ -1035,11 +1038,12 @@ export const gotoNext = (note: any, skipNote?: boolean) => {
   } else {
     gotoCustomNote(num);
   }
-  try {
-    setCursorPosition(note, state.osmd.cursor, 'refresh');
-  } catch (error) {
-    console.log(error);
-  }
+  /* 取消光标了 */
+  // try {
+  //   setCursorPosition(note, state.osmd.cursor, 'refresh');
+  // } catch (error) {
+  //   console.log(error);
+  // }
   fillWordColor();
   // 一行谱,需要滚动小节
   if (state.isSingleLine) {
@@ -1778,22 +1782,26 @@ export const addNoteBBox = (list: any[]) => {
 }
 
 // 给歌词和音符添加动态颜色
+let prevActiveNoteIndex = -1 // 上一个激活的
 export const fillWordColor = () => {
-  // console.log('当前音符',state.activeNoteIndex)
-  state.times.forEach((item: any, idx: number) => {
-    const svgEl = document.getElementById(`vf-${state.times[idx]?.svgElement?.attrs?.id}`)
-    const stemEl = document.getElementById(`vf-${state.times[idx]?.svgElement?.attrs?.id}-stem`)
-    const stemLine = document.getElementById(`vf-${state.times[idx]?.svgElement?.attrs?.id}-lines`)
-    if ((item.i === state.activeNoteIndex || item.id === state.times[state.activeNoteIndex].id) && item.svgElement) {
-      svgEl?.classList.add('noteActive')
-      stemEl?.classList.add('noteActive')
-      stemLine?.classList.add('noteActive')
-    } else {
-      svgEl?.classList.remove('noteActive')
-      stemEl?.classList.remove('noteActive')
-      stemLine?.classList.remove('noteActive')
-    }
-  })
+  // console.log('当前音符',state.activeNoteIndex,prevActiveNoteIndex)
+  if(prevActiveNoteIndex !== -1) {
+    const prevActiveNoteId = state.times[prevActiveNoteIndex]?.svgElement?.attrs?.id
+    const svgEl = document.getElementById(`vf-${prevActiveNoteId}`)
+    const stemEl = document.getElementById(`vf-${prevActiveNoteId}-stem`)
+    const stemLine = document.getElementById(`vf-${prevActiveNoteId}-lines`)
+    svgEl?.classList.remove('noteActive')
+    stemEl?.classList.remove('noteActive')
+    stemLine?.classList.remove('noteActive')
+  }
+  const activeNoteId = state.times[state.activeNoteIndex]?.svgElement?.attrs?.id
+  const svgEl = document.getElementById(`vf-${activeNoteId}`)
+  const stemEl = document.getElementById(`vf-${activeNoteId}-stem`)
+  const stemLine = document.getElementById(`vf-${activeNoteId}-lines`)
+  svgEl?.classList.add('noteActive')
+  stemEl?.classList.add('noteActive')
+  stemLine?.classList.add('noteActive')
+  prevActiveNoteIndex = state.activeNoteIndex
 
   // 给当前匹配到的歌词添加颜色
   const currentNote = state.times[state.activeNoteIndex];

+ 4 - 10
src/view/audio-list/index.tsx

@@ -145,13 +145,7 @@ export const toggleMutePlayAudio = (source: IPlayState, muted: boolean) => {
 /** 切换节拍器音源 */
 export const changeSongSourceByBate = (isDisBate:boolean) => {
 	// isDisBate 为true 切换到不带节拍的,为false 切换到带节拍的
-	let songEleCurrentTime = audioData.songEle?.currentTime || 0
-	let backgroundEleCurrentTime = audioData.backgroundEle?.currentTime || 0
-	let mingSongEleCurrentTime = audioData.mingSongEle?.currentTime || 0
-	// 有一种场景,默认模式没有文件内容的时候,songEle,backgroundEle,mingSongEle都为空,在设置音源之前点击跳转位置,这时候以audioData.progress的时间为准
-	if(!audioData.songEle&&!audioData.backgroundEle&&!audioData.mingSongEle){
-		songEleCurrentTime = backgroundEleCurrentTime = mingSongEleCurrentTime = audioData.progress || 0
-	}
+	const currentTime = audioData.songEle?.currentTime || audioData.backgroundEle?.currentTime || audioData.mingSongEle?.currentTime || audioData.progress || 0
 	if (isDisBate) {
 		if(state.playType === "play"){
 			audioData.songEle = audioData.songCollection.songEle
@@ -172,9 +166,9 @@ export const changeSongSourceByBate = (isDisBate:boolean) => {
 			audioData.mingSongEle = audioData.songCollection.betaMingSongEle || audioData.songCollection.mingSongEle
 		}
 	}
-	audioData.songEle && (audioData.songEle.currentTime = songEleCurrentTime)
-	audioData.backgroundEle && (audioData.backgroundEle.currentTime = backgroundEleCurrentTime)
-	audioData.mingSongEle && (audioData.mingSongEle.currentTime = mingSongEleCurrentTime)
+	audioData.songEle && (audioData.songEle.currentTime = currentTime)
+	audioData.backgroundEle && (audioData.backgroundEle.currentTime = currentTime)
+	audioData.mingSongEle && (audioData.mingSongEle.currentTime = currentTime)
 	// 设置静音与取消静音
 	if (state.playSource === "music") {
 		audioData.songEle && (audioData.songEle.muted = false);

+ 157 - 134
src/view/selection/index.tsx

@@ -255,145 +255,168 @@ export default defineComponent({
 			} catch (error) {}
 		});
 		return () => (
-			<div
-				id="selectionBox"
-				class={[
-					styles.selectionContainer,
-				]}
-				onClick={(e: Event) => e.stopPropagation()}
-			>
-				{selectData.staves.map((item: any) => {
-					// 评测得分
-					const scoreItem = item.id && evaluatingData.evaluatings[item.measureListIndex];
-					// for(let idx in evaluatingData.evaluatings) {
-					// 	const { show, measureIndex } = evaluatingData.evaluatings[idx]
-					// 	if (show && measureIndex !== item.measureListIndex) {
-					// 		evaluatingData.evaluatings[idx].show = false
-					// 	}
-					// }
-					// 高级模式下,显示节拍线
-					// 不是报告模式
-					// 不是多小节休止符
-					// 节拍线开关
-					// 当前小节
-					// 当前小节
-					const lineShow =
-						!state.isReport &&
-						metronomeData.cursorMode === 2 &&
-						item.MeasureNumberXML === metronomeData.activeMetro?.measureNumberXML &&
-						state.times[state.activeNoteIndex].MeasureNumberXML === item.MeasureNumberXML;
-					return (
-						<>
-							{item.staveBox && (
-								<div
-									class={[
-										styles.position,
-										// scoreItem ? `scoreItemLeve${scoreItem.leve}` : "", // 去掉评测小节得分的背景色
-										item.multipleRestMeasures <= 1 ? styles.staveBg : "",
-										(state.platform === IPlatform.PC && state.zoom > 0.8) ? styles.linePC : '',
-									]}
-									style={item.staveBox}
-									onClick={() => handleSelection(item)}
-								>
-									{lineShow && (
-										<div style={{height: selectData.measureHeight + 'px', position: 'relative'}}>
-											<div 
-											class={[
-												styles.line,
-												state.setting.eyeProtection ? styles.eyeLine : '',
-												state.musicRenderType == EnumMusicRenderType.staff ? styles.lineStaff : styles.lineJianPu,
-											]} 
-											style={{ left: metronomeData.activeMetro.left }}></div>
-										</div>
-									)}
-									{!state.isReport &&
-										!!item.multipleRestMeasures &&
-										state.activeMeasureIndex == item.MeasureNumberXML && (
-											<div class={styles.dotWrap}>{item.multipleRestMeasures}</div>
-										)}
-									<Transition
-										name="centerTop"
-										onAfterEnter={() => {
-											scoreItem.show = false;
-										}}
+			<>
+				<div class={styles.staveBgContainer}>
+						{
+							selectData.staves.map((item: any) => {
+								return (
+									<>
+										{
+											item.staveBox && item.multipleRestMeasures <= 1 && 
+												<div 
+													style={{
+														left:item.staveBox.left,
+														top:`calc(${item.staveBox.top} + ${item.staveBox.height})`,
+														width:item.staveBox.width
+													}}
+													class={[styles.staveBg]}
+												></div>
+										}
+									</>
+								)
+							})
+						}
+				</div>
+				<div
+					id="selectionBox"
+					class={[
+						styles.selectionContainer,
+					]}
+					onClick={(e: Event) => e.stopPropagation()}
+				>
+					{selectData.staves.map((item: any, index) => {
+						// 评测得分
+						const scoreItem = item.id && evaluatingData.evaluatings[item.measureListIndex];
+						// for(let idx in evaluatingData.evaluatings) {
+						// 	const { show, measureIndex } = evaluatingData.evaluatings[idx]
+						// 	if (show && measureIndex !== item.measureListIndex) {
+						// 		evaluatingData.evaluatings[idx].show = false
+						// 	}
+						// }
+						// 高级模式下,显示节拍线
+						// 不是报告模式
+						// 不是多小节休止符
+						// 节拍线开关
+						// 当前小节
+						// 当前小节
+						const lineShow =
+							!state.isReport &&
+							metronomeData.cursorMode === 2 &&
+							item.MeasureNumberXML === metronomeData.activeMetro?.measureNumberXML &&
+							state.times[state.activeNoteIndex].MeasureNumberXML === item.MeasureNumberXML;
+						return (
+							<>
+								{item.staveBox && (
+									<div
+										key={item.id}
+										class={[
+											styles.position,
+											// scoreItem ? `scoreItemLeve${scoreItem.leve}` : "", // 去掉评测小节得分的背景色
+											(state.platform === IPlatform.PC && state.zoom > 0.8) ? styles.linePC : '',
+										]}
+										style={item.staveBox}
+										onClick={() => handleSelection(item)}
 									>
-										{scoreItem?.show && (
-											<div
-												class={styles.scoreItem}
-												style={{ color: leveByScoreMeasureIcons[scoreItem.leve]?.color || "" }}
-											>
-												<img src={leveByScoreMeasureIcons[scoreItem.leve]?.icon} />
-												<span>{scoreItem.score}</span>
+										{lineShow && (
+											<div style={{height: selectData.measureHeight + 'px', position: 'relative'}}>
+												<div 
+												class={[
+													styles.line,
+													state.setting.eyeProtection ? styles.eyeLine : '',
+													state.musicRenderType == EnumMusicRenderType.staff ? styles.lineStaff : styles.lineJianPu,
+												]} 
+												style={{ left: metronomeData.activeMetro.left }}></div>
 											</div>
 										)}
-									</Transition>
-								</div>
-							)}
-						</>
-					);
-				})}
-				{selectData.notes.map((item: any) => {
-					return (
-						<div
-							class={[styles.position, disableClickNote.value && styles.disable, styles.note, `noteIndex_${item.index}`]}
-							style={item.bbox}
-							onClick={() => skipNotePlay(item.index)}
-						>
-							{/* <div class={styles.noteFollow} data-vf={"vf" + item.id}>
-								<Icon name="success" />
-								<Icon name="cross" />
-							</div> */}
-							<div class={styles.noteFollow} data-vf={"vf" + item.id}>
-								{/* <Icon name="success" />
-								<Icon name="cross" /> */}
-								<div class={[styles.followTipUp, 'tip-up']}>
-									<img src={IntonationUp} />
-									<span>音准<i>高了</i></span>
-								</div>
-								<div class={[styles.followTipDown, 'tip-down']}>
-									<img src={IntonationDown} />
-									<span>音准<i>低了</i></span>
-								</div>
-							</div>							
-							<div class={[styles.noteDot, 'node-dot']}></div>
-						</div>
-					);
-				})}
-				{/* 选段 */}
-				{
-					sectionPosData.value.map((item,index) =>{
+										{!state.isReport &&
+											!!item.multipleRestMeasures &&
+											state.activeMeasureIndex == item.MeasureNumberXML && (
+												<div class={styles.dotWrap}>{item.multipleRestMeasures}</div>
+											)}
+										<Transition
+											name="centerTop"
+											onAfterEnter={() => {
+												scoreItem.show = false;
+											}}
+										>
+											{scoreItem?.show && (
+												<div
+													class={styles.scoreItem}
+													style={{ color: leveByScoreMeasureIcons[scoreItem.leve]?.color || "" }}
+												>
+													<img src={leveByScoreMeasureIcons[scoreItem.leve]?.icon} />
+													<span>{scoreItem.score}</span>
+												</div>
+											)}
+										</Transition>
+									</div>
+								)}
+							</>
+						);
+					})}
+					{selectData.notes.map((item: any) => {
 						return (
-							item && <div class={styles.selectBox} style={item}>
-								<div class={[styles.selectHandle,index>0&&styles.selectHandleRight,(state.playState==="play" || query.workRecord)&&styles.playIng]} onClick={()=>{
-									// 如果选择了2个 删除左边的时候
-									if(state.section.length===2&&index === 0){
-										state.section = []
-										// 重置速度和播放倍率
-										resetBaseRate(state.activeNoteIndex);
-										showToast({
-											message: "请选择开始小节",
-											duration: 0,
-											position: "top",
-											className: "selectionToast",
-										});
-									}else{
-										state.section.splice(index,1)
-										state.section = [...state.section]  // 触发 watch
-										showToast({
-											message: state.section.length?"请选择结束小节":"请选择开始小节",
-											duration: 0,
-											position: "top",
-											className: "selectionToast",
-										});
-									}
-								}}></div>
+							<div
+								class={[styles.position, disableClickNote.value && styles.disable, styles.note, `noteIndex_${item.index}`]}
+								style={item.bbox}
+								onClick={() => skipNotePlay(item.index)}
+							>
+								{/* <div class={styles.noteFollow} data-vf={"vf" + item.id}>
+									<Icon name="success" />
+									<Icon name="cross" />
+								</div> */}
+								<div class={styles.noteFollow} data-vf={"vf" + item.id}>
+									{/* <Icon name="success" />
+									<Icon name="cross" /> */}
+									<div class={[styles.followTipUp, 'tip-up']}>
+										<img src={IntonationUp} />
+										<span>音准<i>高了</i></span>
+									</div>
+									<div class={[styles.followTipDown, 'tip-down']}>
+										<img src={IntonationDown} />
+										<span>音准<i>低了</i></span>
+									</div>
+								</div>							
+								<div class={[styles.noteDot, 'node-dot']}></div>
 							</div>
-						)
-					})
-				}
-				{/* 移动模块 */}
-				{query.isMove == "1" && <MoveMusicScore />}
-			</div>
+						);
+					})}
+					{/* 选段 */}
+					{
+						sectionPosData.value.map((item,index) =>{
+							return (
+								item && <div class={styles.selectBox} style={item}>
+									<div class={[styles.selectHandle,index>0&&styles.selectHandleRight,(state.playState==="play" || query.workRecord)&&styles.playIng]} onClick={()=>{
+										// 如果选择了2个 删除左边的时候
+										if(state.section.length===2&&index === 0){
+											state.section = []
+											// 重置速度和播放倍率
+											resetBaseRate(state.activeNoteIndex);
+											showToast({
+												message: "请选择开始小节",
+												duration: 0,
+												position: "top",
+												className: "selectionToast",
+											});
+										}else{
+											state.section.splice(index,1)
+											state.section = [...state.section]  // 触发 watch
+											showToast({
+												message: state.section.length?"请选择结束小节":"请选择开始小节",
+												duration: 0,
+												position: "top",
+												className: "selectionToast",
+											});
+										}
+									}}></div>
+								</div>
+							)
+						})
+					}
+					{/* 移动模块 */}
+					{query.isMove == "1" && <MoveMusicScore />}
+				</div>
+			</>
 		);
 	},
 });