|  | @@ -1,11 +1,12 @@
 | 
											
												
													
														|  | -import { showToast, Toast } from "vant";
 |  | 
 | 
											
												
													
														|  | -import { reactive, watchEffect } from "vue";
 |  | 
 | 
											
												
													
														|  | 
 |  | +import { showToast } from "vant";
 | 
											
												
													
														|  | 
 |  | +import { reactive } from "vue";
 | 
											
												
													
														|  |  import { OpenSheetMusicDisplay } from "../osmd-extended/src";
 |  |  import { OpenSheetMusicDisplay } from "../osmd-extended/src";
 | 
											
												
													
														|  | -import _event, { EventEnum } from "./helpers/eventemitter";
 |  | 
 | 
											
												
													
														|  |  import { metronomeData } from "./helpers/metronome";
 |  |  import { metronomeData } from "./helpers/metronome";
 | 
											
												
													
														|  | -import { GradualNote, GradualTimes, GradualVersion, IMode } from "./type";
 |  | 
 | 
											
												
													
														|  | -import { handleEndBegin, sendEvaluatingOffsetTime } from "./view/evaluating";
 |  | 
 | 
											
												
													
														|  | 
 |  | +import { GradualNote, GradualTimes, GradualVersion } from "./type";
 | 
											
												
													
														|  | 
 |  | +import { handleEndBegin, handleStartEvaluat, sendEvaluatingOffsetTime } from "./view/evaluating";
 | 
											
												
													
														|  |  import { IFingering } from "src/view/fingering/fingering-config";
 |  |  import { IFingering } from "src/view/fingering/fingering-config";
 | 
											
												
													
														|  | 
 |  | +import { handleStartTick } from "./view/tick";
 | 
											
												
													
														|  | 
 |  | +import { audioListStart, getAudioCurrentTime, getAudioDuration, setAudioCurrentTime, setAudioPlaybackRate } from "./view/audio-list";
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |  /** 入门 | 进阶 | 大师 */
 |  |  /** 入门 | 进阶 | 大师 */
 | 
											
												
													
														|  |  export type IDifficulty = "BEGINNER" | "ADVANCED" | "PERFORMER";
 |  |  export type IDifficulty = "BEGINNER" | "ADVANCED" | "PERFORMER";
 | 
											
										
											
												
													
														|  | @@ -70,10 +71,6 @@ const state = reactive({
 | 
											
												
													
														|  |  	activeNoteIndex: 0,
 |  |  	activeNoteIndex: 0,
 | 
											
												
													
														|  |  	/** 激活的小节 */
 |  |  	/** 激活的小节 */
 | 
											
												
													
														|  |  	activeMeasureIndex: 0,
 |  |  	activeMeasureIndex: 0,
 | 
											
												
													
														|  | -	/** 原音ref */
 |  | 
 | 
											
												
													
														|  | -	songEl: null as unknown as HTMLAudioElement,
 |  | 
 | 
											
												
													
														|  | -	/** 背景音乐ref */
 |  | 
 | 
											
												
													
														|  | -	backgroundEl: null as unknown as HTMLAudioElement,
 |  | 
 | 
											
												
													
														|  |  	/** 选段状态 */
 |  |  	/** 选段状态 */
 | 
											
												
													
														|  |  	sectionStatus: false,
 |  |  	sectionStatus: false,
 | 
											
												
													
														|  |  	/** 选段数据 */
 |  |  	/** 选段数据 */
 | 
											
										
											
												
													
														|  | @@ -117,39 +114,14 @@ const state = reactive({
 | 
											
												
													
														|  |  	fixtime: 0,
 |  |  	fixtime: 0,
 | 
											
												
													
														|  |  	/** 指法信息 */
 |  |  	/** 指法信息 */
 | 
											
												
													
														|  |  	fingeringInfo: {} as IFingering,
 |  |  	fingeringInfo: {} as IFingering,
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -	repeatedBeats: 0,
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -	maskStatus: false,
 |  | 
 | 
											
												
													
														|  | -	timesById: {} as any,
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -	activeTick: -1,
 |  | 
 | 
											
												
													
														|  | -	activeTickRepeat: 1,
 |  | 
 | 
											
												
													
														|  | -	showTick: false,
 |  | 
 | 
											
												
													
														|  | -	isSpecialShapedScreen: false,
 |  | 
 | 
											
												
													
														|  | -	notchHeight: 0,
 |  | 
 | 
											
												
													
														|  | -	fixedKey: 0,
 |  | 
 | 
											
												
													
														|  | -	renderLoading: false,
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -	isPauseRecording: false,
 |  | 
 | 
											
												
													
														|  | -	feeShow: false,
 |  | 
 | 
											
												
													
														|  | -	vipShow: false,
 |  | 
 | 
											
												
													
														|  | -	mode: "contact" as IMode,
 |  | 
 | 
											
												
													
														|  | -	activeSpeed: 90 as number, // 当前速度
 |  | 
 | 
											
												
													
														|  | -	baseSpeed: 90 as number, // 基准速度
 |  | 
 | 
											
												
													
														|  | -	activeDetail: null as any,
 |  | 
 | 
											
												
													
														|  | -	// 是否跳过节拍器时间
 |  | 
 | 
											
												
													
														|  | -	skipTick: false,
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -	sectionFlash: false,
 |  | 
 | 
											
												
													
														|  | -	befireSection: null as any,
 |  | 
 | 
											
												
													
														|  | 
 |  | +	/** 滚动容器的ID */
 | 
											
												
													
														|  | 
 |  | +	scrollContainer: "musicAndSelection",
 | 
											
												
													
														|  |  	/** 是否是打击乐 */
 |  |  	/** 是否是打击乐 */
 | 
											
												
													
														|  |  	isPercussion: false,
 |  |  	isPercussion: false,
 | 
											
												
													
														|  | -	isAppPlay: false, // 是否是app播放
 |  | 
 | 
											
												
													
														|  | -	partListNames: [] as string[], // 当前曲谱中所有声部名字
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -	midiPlayIniting: false, // midi播放器是否初始化中
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | 
 |  | +	/** 是否重复节拍器的时间 */
 | 
											
												
													
														|  | 
 |  | +	repeatedBeats: 0,
 | 
											
												
													
														|  | 
 |  | +	/**当前曲谱中所有声部名字 */
 | 
											
												
													
														|  | 
 |  | +	partListNames: [] as string[],
 | 
											
												
													
														|  |  	/** 渐变速度信息 */
 |  |  	/** 渐变速度信息 */
 | 
											
												
													
														|  |  	gradual: [] as GradualNote[],
 |  |  	gradual: [] as GradualNote[],
 | 
											
												
													
														|  |  	/** 渐变速度版本 */
 |  |  	/** 渐变速度版本 */
 | 
											
										
											
												
													
														|  | @@ -184,7 +156,7 @@ const setStep = () => {
 | 
											
												
													
														|  |  export const onPlay = () => {
 |  |  export const onPlay = () => {
 | 
											
												
													
														|  |  	setStep();
 |  |  	setStep();
 | 
											
												
													
														|  |  	if (state.modeType === "evaluating") {
 |  |  	if (state.modeType === "evaluating") {
 | 
											
												
													
														|  | -		const currentTime = state.songEl?.currentTime || 0;
 |  | 
 | 
											
												
													
														|  | 
 |  | +		const currentTime = getAudioCurrentTime();
 | 
											
												
													
														|  |  		sendEvaluatingOffsetTime(currentTime);
 |  |  		sendEvaluatingOffsetTime(currentTime);
 | 
											
												
													
														|  |  	}
 |  |  	}
 | 
											
												
													
														|  |  };
 |  |  };
 | 
											
										
											
												
													
														|  | @@ -209,32 +181,31 @@ export const onEnded = () => {
 | 
											
												
													
														|  |   * 播放一直触发的事件
 |  |   * 播放一直触发的事件
 | 
											
												
													
														|  |   */
 |  |   */
 | 
											
												
													
														|  |  const handlePlaying = (_item?: any) => {
 |  |  const handlePlaying = (_item?: any) => {
 | 
											
												
													
														|  | -	if (state.songEl) {
 |  | 
 | 
											
												
													
														|  | -		const currentTime = state.songEl.currentTime;
 |  | 
 | 
											
												
													
														|  | -		state.playProgress = (currentTime / state.songEl.duration) * 100;
 |  | 
 | 
											
												
													
														|  | -		const item = _item ? _item : getNote(currentTime);
 |  | 
 | 
											
												
													
														|  | 
 |  | +	const currentTime = getAudioCurrentTime();
 | 
											
												
													
														|  | 
 |  | +	const duration = getAudioDuration();
 | 
											
												
													
														|  | 
 |  | +	state.playProgress = (currentTime / duration) * 100;
 | 
											
												
													
														|  | 
 |  | +	const item = _item ? _item : getNote(currentTime);
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  | -		if (item) {
 |  | 
 | 
											
												
													
														|  | -			// 选段状态下
 |  | 
 | 
											
												
													
														|  | -			if (state.sectionStatus && state.section.length === 2) {
 |  | 
 | 
											
												
													
														|  | -				let startItemIndex = state.section[0].index;
 |  | 
 | 
											
												
													
														|  | -				let startXmlIndex = state.section[0].MeasureNumberXML;
 |  | 
 | 
											
												
													
														|  | -				// 开启预备拍
 |  | 
 | 
											
												
													
														|  | -				if (state.sectionFirst) {
 |  | 
 | 
											
												
													
														|  | -					startItemIndex = state.sectionFirst.i;
 |  | 
 | 
											
												
													
														|  | -					startXmlIndex = state.sectionFirst.MeasureNumberXML;
 |  | 
 | 
											
												
													
														|  | -				}
 |  | 
 | 
											
												
													
														|  | -				if (item.MeasureNumberXML < startXmlIndex || item.MeasureNumberXML > state.section[1].MeasureNumberXML) {
 |  | 
 | 
											
												
													
														|  | -					// console.log('选段播放结束')
 |  | 
 | 
											
												
													
														|  | -					skipNotePlay(startItemIndex);
 |  | 
 | 
											
												
													
														|  | -					return;
 |  | 
 | 
											
												
													
														|  | -				}
 |  | 
 | 
											
												
													
														|  | 
 |  | +	if (item) {
 | 
											
												
													
														|  | 
 |  | +		// 选段状态下
 | 
											
												
													
														|  | 
 |  | +		if (state.sectionStatus && state.section.length === 2) {
 | 
											
												
													
														|  | 
 |  | +			let startItemIndex = state.section[0].index;
 | 
											
												
													
														|  | 
 |  | +			let startXmlIndex = state.section[0].MeasureNumberXML;
 | 
											
												
													
														|  | 
 |  | +			// 开启预备拍
 | 
											
												
													
														|  | 
 |  | +			if (state.sectionFirst) {
 | 
											
												
													
														|  | 
 |  | +				startItemIndex = state.sectionFirst.i;
 | 
											
												
													
														|  | 
 |  | +				startXmlIndex = state.sectionFirst.MeasureNumberXML;
 | 
											
												
													
														|  | 
 |  | +			}
 | 
											
												
													
														|  | 
 |  | +			if (item.MeasureNumberXML < startXmlIndex || item.MeasureNumberXML > state.section[1].MeasureNumberXML) {
 | 
											
												
													
														|  | 
 |  | +				// console.log('选段播放结束')
 | 
											
												
													
														|  | 
 |  | +				skipNotePlay(startItemIndex);
 | 
											
												
													
														|  | 
 |  | +				return;
 | 
											
												
													
														|  |  			}
 |  |  			}
 | 
											
												
													
														|  | -			gotoNext(item);
 |  | 
 | 
											
												
													
														|  |  		}
 |  |  		}
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -		metronomeData.metro?.sound(currentTime);
 |  | 
 | 
											
												
													
														|  | 
 |  | +		gotoNext(item);
 | 
											
												
													
														|  |  	}
 |  |  	}
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +	metronomeData.metro?.sound(currentTime);
 | 
											
												
													
														|  |  };
 |  |  };
 | 
											
												
													
														|  |  /** 跳转到指定音符开始播放 */
 |  |  /** 跳转到指定音符开始播放 */
 | 
											
												
													
														|  |  export const skipNotePlay = (itemIndex: number, isStart = false) => {
 |  |  export const skipNotePlay = (itemIndex: number, isStart = false) => {
 | 
											
										
											
												
													
														|  | @@ -245,8 +216,7 @@ export const skipNotePlay = (itemIndex: number, isStart = false) => {
 | 
											
												
													
														|  |  	}
 |  |  	}
 | 
											
												
													
														|  |  	// console.log("🚀 ~ itemTime:", itemTime);
 |  |  	// console.log("🚀 ~ itemTime:", itemTime);
 | 
											
												
													
														|  |  	if (item) {
 |  |  	if (item) {
 | 
											
												
													
														|  | -		state.songEl && (state.songEl.currentTime = itemTime);
 |  | 
 | 
											
												
													
														|  | -		state.backgroundEl && (state.backgroundEl.currentTime = itemTime);
 |  | 
 | 
											
												
													
														|  | 
 |  | +		setAudioCurrentTime(itemTime)
 | 
											
												
													
														|  |  		handlePlaying(item);
 |  |  		handlePlaying(item);
 | 
											
												
													
														|  |  	}
 |  |  	}
 | 
											
												
													
														|  |  };
 |  |  };
 | 
											
										
											
												
													
														|  | @@ -255,25 +225,24 @@ export const skipNotePlay = (itemIndex: number, isStart = false) => {
 | 
											
												
													
														|  |   * 切换曲谱播放状态
 |  |   * 切换曲谱播放状态
 | 
											
												
													
														|  |   * @param playState 可选: 默认 undefined, 需要切换的状态 play:播放, paused: 暂停
 |  |   * @param playState 可选: 默认 undefined, 需要切换的状态 play:播放, paused: 暂停
 | 
											
												
													
														|  |   */
 |  |   */
 | 
											
												
													
														|  | -export const togglePlay = (playState?: "play" | "paused") => {
 |  | 
 | 
											
												
													
														|  | 
 |  | +export const togglePlay = async (playState?: "play" | "paused") => {
 | 
											
												
													
														|  |  	state.playState = playState ? playState : state.playState === "paused" ? "play" : "paused";
 |  |  	state.playState = playState ? playState : state.playState === "paused" ? "play" : "paused";
 | 
											
												
													
														|  | 
 |  | +	if (state.playState === "play" && state.needTick) {
 | 
											
												
													
														|  | 
 |  | +		const tickend = await handleStartTick();
 | 
											
												
													
														|  | 
 |  | +		// console.log("🚀 ~ tickend:", tickend)
 | 
											
												
													
														|  | 
 |  | +	}
 | 
											
												
													
														|  |  	if (state.playState == "play") {
 |  |  	if (state.playState == "play") {
 | 
											
												
													
														|  |  		// 如果没有选段结束开始播放,清空选段状态
 |  |  		// 如果没有选段结束开始播放,清空选段状态
 | 
											
												
													
														|  |  		if (state.sectionStatus && state.section.length < 2) {
 |  |  		if (state.sectionStatus && state.section.length < 2) {
 | 
											
												
													
														|  |  			clearSelection();
 |  |  			clearSelection();
 | 
											
												
													
														|  |  		}
 |  |  		}
 | 
											
												
													
														|  | -		state.songEl?.play();
 |  | 
 | 
											
												
													
														|  | -		state.backgroundEl?.play();
 |  | 
 | 
											
												
													
														|  | -	} else {
 |  | 
 | 
											
												
													
														|  | -		state.songEl?.pause();
 |  | 
 | 
											
												
													
														|  | -		state.backgroundEl?.pause();
 |  | 
 | 
											
												
													
														|  |  	}
 |  |  	}
 | 
											
												
													
														|  | 
 |  | +	audioListStart(state.playState);
 | 
											
												
													
														|  |  };
 |  |  };
 | 
											
												
													
														|  |  /** 结束播放 */
 |  |  /** 结束播放 */
 | 
											
												
													
														|  |  export const handleStopPlay = () => {
 |  |  export const handleStopPlay = () => {
 | 
											
												
													
														|  |  	state.playState = "paused";
 |  |  	state.playState = "paused";
 | 
											
												
													
														|  | -	state.songEl?.pause();
 |  | 
 | 
											
												
													
														|  | -	state.backgroundEl?.pause();
 |  | 
 | 
											
												
													
														|  | 
 |  | +	audioListStart(state.playState);
 | 
											
												
													
														|  |  	skipNotePlay(0, true);
 |  |  	skipNotePlay(0, true);
 | 
											
												
													
														|  |  };
 |  |  };
 | 
											
												
													
														|  |  
 |  |  
 | 
											
										
											
												
													
														|  | @@ -345,8 +314,7 @@ export const handleSetSpeed = (speed: number) => {
 | 
											
												
													
														|  |  	console.log("🚀 ~ playbackRate:", speed, state.originSpeed);
 |  |  	console.log("🚀 ~ playbackRate:", speed, state.originSpeed);
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |  	// 按照比例设置速度
 |  |  	// 按照比例设置速度
 | 
											
												
													
														|  | -	state.songEl && (state.songEl.playbackRate = playbackRate);
 |  | 
 | 
											
												
													
														|  | -	state.backgroundEl && (state.backgroundEl.playbackRate = playbackRate);
 |  | 
 | 
											
												
													
														|  | 
 |  | +	setAudioPlaybackRate(playbackRate);
 | 
											
												
													
														|  |  };
 |  |  };
 | 
											
												
													
														|  |  /** 清除选段状态 */
 |  |  /** 清除选段状态 */
 | 
											
												
													
														|  |  export const clearSelection = () => {
 |  |  export const clearSelection = () => {
 | 
											
										
											
												
													
														|  | @@ -399,7 +367,7 @@ export const handleSelection = (item: any) => {
 | 
											
												
													
														|  |  		state.sectionToast.message = "请选择结束小节";
 |  |  		state.sectionToast.message = "请选择结束小节";
 | 
											
												
													
														|  |  	}
 |  |  	}
 | 
											
												
													
														|  |  };
 |  |  };
 | 
											
												
													
														|  | -let offsetTop = 0
 |  | 
 | 
											
												
													
														|  | 
 |  | +let offsetTop = 0;
 | 
											
												
													
														|  |  /**
 |  |  /**
 | 
											
												
													
														|  |   * 窗口内滚动到音符的区域
 |  |   * 窗口内滚动到音符的区域
 | 
											
												
													
														|  |   * @param isScroll 可选: 强制滚动到顶部, 默认: false
 |  |   * @param isScroll 可选: 强制滚动到顶部, 默认: false
 | 
											
										
											
												
													
														|  | @@ -407,9 +375,9 @@ let offsetTop = 0
 | 
											
												
													
														|  |   */
 |  |   */
 | 
											
												
													
														|  |  export const scrollViewNote = () => {
 |  |  export const scrollViewNote = () => {
 | 
											
												
													
														|  |  	const cursorElement = document.getElementById("cursorImg-0")!;
 |  |  	const cursorElement = document.getElementById("cursorImg-0")!;
 | 
											
												
													
														|  | -	const musicAndSelection = document.getElementById("musicAndSelection")!;
 |  | 
 | 
											
												
													
														|  | 
 |  | +	const musicAndSelection = document.getElementById(state.scrollContainer)!;
 | 
											
												
													
														|  |  	if (!cursorElement || !musicAndSelection || offsetTop === cursorElement.offsetTop) return;
 |  |  	if (!cursorElement || !musicAndSelection || offsetTop === cursorElement.offsetTop) return;
 | 
											
												
													
														|  | -	offsetTop = cursorElement.offsetTop
 |  | 
 | 
											
												
													
														|  | 
 |  | +	offsetTop = cursorElement.offsetTop;
 | 
											
												
													
														|  |  	if (cursorElement.offsetTop > 50) {
 |  |  	if (cursorElement.offsetTop > 50) {
 | 
											
												
													
														|  |  		musicAndSelection.scrollTo({
 |  |  		musicAndSelection.scrollTo({
 | 
											
												
													
														|  |  			top: cursorElement.offsetTop - 25,
 |  |  			top: cursorElement.offsetTop - 25,
 | 
											
										
											
												
													
														|  | @@ -427,4 +395,13 @@ export const scrollViewNote = () => {
 | 
											
												
													
														|  |  export const isRhythmicExercises = () => {
 |  |  export const isRhythmicExercises = () => {
 | 
											
												
													
														|  |  	return state.examSongName.indexOf("节奏练习") > -1;
 |  |  	return state.examSongName.indexOf("节奏练习") > -1;
 | 
											
												
													
														|  |  };
 |  |  };
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +/** 重置状态 */
 | 
											
												
													
														|  | 
 |  | +export const handleRessetState = () => {
 | 
											
												
													
														|  | 
 |  | +	if (state.modeType === "evaluating") {
 | 
											
												
													
														|  | 
 |  | +		handleStartEvaluat();
 | 
											
												
													
														|  | 
 |  | +	} else if (state.modeType === "practise") {
 | 
											
												
													
														|  | 
 |  | +		togglePlay("paused");
 | 
											
												
													
														|  | 
 |  | +	}
 | 
											
												
													
														|  | 
 |  | +};
 | 
											
												
													
														|  |  export default state;
 |  |  export default state;
 |