|  | @@ -14,6 +14,8 @@ import {
 | 
	
		
			
				|  |  |  	OpenSheetMusicDisplay,
 | 
	
		
			
				|  |  |  } from "/osmd-extended/src";
 | 
	
		
			
				|  |  |  import { GradualChange, speedInfo } from "./calcSpeed";
 | 
	
		
			
				|  |  | +import { beatUnitTo, speedBeatTo } from "/src/helpers/beatConfig"
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  const browserInfo = browser();
 | 
	
		
			
				|  |  |  dayjs.extend(duration);
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -686,11 +688,19 @@ export const formatXML = (xml: string, xmlUrl?: string): string => {
 | 
	
		
			
				|  |  |  		state.originSpeed = speeds[0] ? speeds[0] : 100;
 | 
	
		
			
				|  |  |  		state.speed = state.originSpeed;
 | 
	
		
			
				|  |  |  	}
 | 
	
		
			
				|  |  | +	// 赋值谱面速度节拍器,没有的时候 以后台传入的为准
 | 
	
		
			
				|  |  | +	const metronomeXml = xmlParse.getElementsByTagName('metronome')?.[0]
 | 
	
		
			
				|  |  | +	const beatUnit = metronomeXml?.getElementsByTagName('beat-unit')?.[0]?.textContent || ''
 | 
	
		
			
				|  |  | +	if(beatUnit){
 | 
	
		
			
				|  |  | +		const beatUnitDot = metronomeXml?.getElementsByTagName('beat-unit-dot')?.[0]
 | 
	
		
			
				|  |  | +		state.speedBeatUnit = beatUnitTo(beatUnit, !!beatUnitDot)
 | 
	
		
			
				|  |  | +	}	
 | 
	
		
			
				|  |  |  	// 如果谱面和小节都没有打速度,osmd设置的小节速度默认取后台设置的速度
 | 
	
		
			
				|  |  |  	if (speeds.length === 0) {
 | 
	
		
			
				|  |  |  		;(window as any).baseMeasureSpeed = state.originSpeed
 | 
	
		
			
				|  |  |  	} else {
 | 
	
		
			
				|  |  | -		state.originAudioPlayRate = speeds[0] / state.originSpeed
 | 
	
		
			
				|  |  | +		// 当前谱面的速度转为4分音符速度 因为我们速度比例转为4分音符了
 | 
	
		
			
				|  |  | +		state.originAudioPlayRate = speedBeatTo({unit:state.speedBeatUnit, speed:speeds[0]}, "1/4") / state.originSpeed
 | 
	
		
			
				|  |  |  	}
 | 
	
		
			
				|  |  |  	console.log('是否是变速的曲子:',hasVaryingSpeed,speeds)
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -879,6 +889,7 @@ export const formateTimes = (osmd: OpenSheetMusicDisplay) => {
 | 
	
		
			
				|  |  |  	let preNoteEndTime = 0; // 上一个音符的结束时间
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  	let preNoteMeasureNumber: any = null; // 上一个小节的number值
 | 
	
		
			
				|  |  | +	let currentRealTempo: any = {}; // 当前小节的速度与拍号信息
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  	let _notes = [] as any[];
 | 
	
		
			
				|  |  |  	if (state.gradualTimes) {
 | 
	
	
		
			
				|  | @@ -992,6 +1003,9 @@ export const formateTimes = (osmd: OpenSheetMusicDisplay) => {
 | 
	
		
			
				|  |  |  			}
 | 
	
		
			
				|  |  |  			note.maxNoteNum = maxNoteNum;
 | 
	
		
			
				|  |  |  			note.trackIndex = minIndex;
 | 
	
		
			
				|  |  | +			currentRealTempo = iterator.currentMeasure.tempoExpressions.length ? iterator.currentMeasure.tempoExpressions.find((item: any) => item?.InstantaneousTempo?.isMetronomeMark)?.InstantaneousTempo || currentRealTempo : currentRealTempo;
 | 
	
		
			
				|  |  | +			const { beatUnit="quarter", dotted=false, tempoInBpm=state.originSpeed } = currentRealTempo
 | 
	
		
			
				|  |  | +			const speedBeatUnit = beatUnitTo(beatUnit, dotted)			
 | 
	
		
			
				|  |  |  			_notes.push({
 | 
	
		
			
				|  |  |  				measureNum: note?.sourceMeasure?.MeasureNumberXML,
 | 
	
		
			
				|  |  |  				note,
 | 
	
	
		
			
				|  | @@ -999,7 +1013,11 @@ export const formateTimes = (osmd: OpenSheetMusicDisplay) => {
 | 
	
		
			
				|  |  |  				currentTime,
 | 
	
		
			
				|  |  |  				isDouble,
 | 
	
		
			
				|  |  |  				isMutileSubject,
 | 
	
		
			
				|  |  | -				measuresTempoInBPM: note?.sourceMeasure?.tempoInBPM,
 | 
	
		
			
				|  |  | +				// measuresTempoInBPM: note?.sourceMeasure?.tempoInBPM,
 | 
	
		
			
				|  |  | +				// 转换成1/4拍的速度
 | 
	
		
			
				|  |  | +				measuresTempoInBPM: speedBeatTo({unit: speedBeatUnit || "1/4",speed: tempoInBpm || 0}, `1/4`),
 | 
	
		
			
				|  |  | +				speedBeatUnit, // 当前谱面小节的速度对应的是几分音符
 | 
	
		
			
				|  |  | +				currentRealTempo
 | 
	
		
			
				|  |  |  			});
 | 
	
		
			
				|  |  |  		}
 | 
	
		
			
				|  |  |  		iterator.moveToNextVisibleVoiceEntry(false);
 | 
	
	
		
			
				|  | @@ -1018,7 +1036,7 @@ export const formateTimes = (osmd: OpenSheetMusicDisplay) => {
 | 
	
		
			
				|  |  |  	console.log('变速曲子',hasVaryingSpeed, _notes)
 | 
	
		
			
				|  |  |  	let noteIds: any = [];
 | 
	
		
			
				|  |  |  	// let voicesBBox: any = null;
 | 
	
		
			
				|  |  | -	for (let { note, iterator, currentTime, isDouble, isMutileSubject } of _notes) {
 | 
	
		
			
				|  |  | +	for (let { note, iterator, currentTime, isDouble, isMutileSubject, speedBeatUnit, measuresTempoInBPM } of _notes) {
 | 
	
		
			
				|  |  |  		if (note) {
 | 
	
		
			
				|  |  |  			if (preMeasureNumber != note?.sourceMeasure?.MeasureNumberXML) {
 | 
	
		
			
				|  |  |  				si = 0
 | 
	
	
		
			
				|  | @@ -1126,12 +1144,15 @@ export const formateTimes = (osmd: OpenSheetMusicDisplay) => {
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  			let beatSpeed = 0;
 | 
	
		
			
				|  |  |  			// 速度不能为0 此处的速度应该是按照设置的速度而不是校准后的速度,否则mp3速度不对
 | 
	
		
			
				|  |  | -			if (measureSpeed !== baseSpeed && !hasVaryingSpeed) {
 | 
	
		
			
				|  |  | -				beatSpeed = baseSpeed || measureSpeed || 100
 | 
	
		
			
				|  |  | -			} else {
 | 
	
		
			
				|  |  | -				beatSpeed = (state.isSpecialBookCategory ? measureSpeed : baseSpeed) || 1;
 | 
	
		
			
				|  |  | -			}
 | 
	
		
			
				|  |  | +			// if (measureSpeed !== baseSpeed && !hasVaryingSpeed) {
 | 
	
		
			
				|  |  | +			// 	beatSpeed = baseSpeed || measureSpeed || 100
 | 
	
		
			
				|  |  | +			// } else {
 | 
	
		
			
				|  |  | +			// 	beatSpeed = (state.isSpecialBookCategory ? measureSpeed : baseSpeed) || 1;
 | 
	
		
			
				|  |  | +			// }
 | 
	
		
			
				|  |  | +			// 计算音符时值,使用转换成1/4的速度计算
 | 
	
		
			
				|  |  | +			beatSpeed = measuresTempoInBPM;
 | 
	
		
			
				|  |  |  			// let beatSpeed = measureSpeed || baseSpeed
 | 
	
		
			
				|  |  | +			beatSpeed = beatSpeed / state.originAudioPlayRate;
 | 
	
		
			
				|  |  |  			// 如果有节拍器,需要将节拍器的时间算出来
 | 
	
		
			
				|  |  |  			if (i === 0) {
 | 
	
		
			
				|  |  |  				if(state.isOpenMetronome){
 | 
	
	
		
			
				|  | @@ -1438,7 +1459,9 @@ export const formateTimes = (osmd: OpenSheetMusicDisplay) => {
 | 
	
		
			
				|  |  |  				stave,
 | 
	
		
			
				|  |  |  				firstVerticalMeasure: activeVerticalMeasureList[0],
 | 
	
		
			
				|  |  |  				noteLength: 1,
 | 
	
		
			
				|  |  | -				speedbeatUnit: beatUnit,
 | 
	
		
			
				|  |  | +				osdmContext: osmd,
 | 
	
		
			
				|  |  | +				// speedbeatUnit: beatUnit,
 | 
	
		
			
				|  |  | +				speedBeatUnit,
 | 
	
		
			
				|  |  |  				multipleRestMeasures: multipleRestMeasures, // 当前合并小节的索引,从1开始到当前的totalMultipleRestMeasures结束,
 | 
	
		
			
				|  |  |  				totalMultipleRestMeasures, // 当前小节总的合并小节数
 | 
	
		
			
				|  |  |  				measureSpeed,  // 小节速度
 | 
	
	
		
			
				|  | @@ -1471,7 +1494,7 @@ export const formateTimes = (osmd: OpenSheetMusicDisplay) => {
 | 
	
		
			
				|  |  |  						nodeDetail.frequencyList.push(cnote.pitch.frequency)
 | 
	
		
			
				|  |  |  					}
 | 
	
		
			
				|  |  |  				})
 | 
	
		
			
				|  |  | -			}			
 | 
	
		
			
				|  |  | +			}
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  			const firstRepeatNodeId = allNotes.find((item: any) => item.MeasureNumberXML === state.timegapRepeatMeasureIndex)?.noteId || 0;
 | 
	
		
			
				|  |  |  			if (state.isEvxml && nodeDetail.repeatIdx && nodeDetail.i > 0 && nodeDetail.MeasureNumberXML === state.timegapRepeatMeasureIndex && nodeDetail.noteId === firstRepeatNodeId) {
 |