|
@@ -144,6 +144,12 @@ const state = reactive({
|
|
|
basePlayRate: 1,
|
|
|
/** 播放中,更加当前小节速度动态计算的展示速度 */
|
|
|
playIngSpeed: 90,
|
|
|
+ /** 上一次app返回的播放进度 */
|
|
|
+ preAppAudioPlayTime: 0,
|
|
|
+ /** app返回的音频文件总时长 */
|
|
|
+ appAudioTotalTime: 0,
|
|
|
+ /** 播放倍率不等于1,或者是选段评测,APP暂时不支持保存演奏,需要给出提示 */
|
|
|
+ initShow: true,
|
|
|
})
|
|
|
|
|
|
const syncStepIndex = (i: number) => {
|
|
@@ -235,6 +241,7 @@ export const getActiveMidiId = () => {
|
|
|
* @param val IMode
|
|
|
*/
|
|
|
export const changeMode = async (val: IMode, type?: string | undefined) => {
|
|
|
+ // console.log('切换音源',val,state.songs)
|
|
|
const cm: IMode = val === 'background' ? 'music' : 'background'
|
|
|
// console.log(!state.songs[val], val, cm)
|
|
|
if (detailState.activeDetail.isAppPlay) {
|
|
@@ -270,6 +277,10 @@ export const changeMode = async (val: IMode, type?: string | undefined) => {
|
|
|
// return
|
|
|
// }
|
|
|
state.mode = val
|
|
|
+ // 如果没有伴奏,音源切换按钮文案重置为原音
|
|
|
+ if (!state.songs.background) {
|
|
|
+ state.mode = 'music'
|
|
|
+ }
|
|
|
if (type === 'all') {
|
|
|
state.audiosInstance?.setMute(true, state.songs[cm])
|
|
|
state.audiosInstance?.setMute(true, state.songs[val])
|
|
@@ -324,7 +335,7 @@ export const changeSpeed = (speed: number, isSave: boolean = true) => {
|
|
|
state.speed = speed
|
|
|
state.playIngSpeed = speed
|
|
|
// 当前的音符
|
|
|
- const currentItem: any = detailState.times[state.activeIndex];
|
|
|
+ const currentItem: any = (detailState.sectionStatus && detailState.section.length === 2) ? detailState.section[0] : detailState.times[state.activeIndex];
|
|
|
state.basePlayRate = currentItem?.measureSpeed ? state.speed / currentItem.measureSpeed : state.speed / detailState.baseSpeed;
|
|
|
if (!detailState.activeDetail) return
|
|
|
state.audiosInstance?.setSpeed(state.basePlayRate)
|
|
@@ -389,7 +400,7 @@ export const refreshIndexBase = (index: number) => {
|
|
|
|
|
|
// 练习模式下,开始播放时,记录mp3的播放倍率
|
|
|
export const initSetPlayRate = () => {
|
|
|
- const item: any = detailState.times[state.activeIndex];
|
|
|
+ const item: any = (detailState.sectionStatus && detailState.section.length === 2) ? detailState.section[0] : detailState.times[state.activeIndex];
|
|
|
if (item && modelType.value === "practice" && item.measureSpeed) {
|
|
|
const ratio = state.speed / item.measureSpeed
|
|
|
// state.audiosInstance?.setSpeed(ratio)
|
|
@@ -402,7 +413,10 @@ export const initSetPlayRate = () => {
|
|
|
const dynamicShowPlaySpeed = (index: number) => {
|
|
|
const item: any = detailState.times[index];
|
|
|
|
|
|
- if (item && modelType.value === "practice" && state.playState === "play" && item.measureSpeed ) {
|
|
|
+ // if (item && state.playState === "play" && item.measureSpeed ) {
|
|
|
+ // state.playIngSpeed = Math.floor(state.basePlayRate * item.measureSpeed)
|
|
|
+ // }
|
|
|
+ if (item && item.measureSpeed ) {
|
|
|
state.playIngSpeed = Math.floor(state.basePlayRate * item.measureSpeed)
|
|
|
}
|
|
|
}
|
|
@@ -410,14 +424,23 @@ const dynamicShowPlaySpeed = (index: number) => {
|
|
|
export const refreshIndex = (ctime?: number) => {
|
|
|
const { osmd }: any = state
|
|
|
if (osmd && (ctime || state.audiosInstance.audio)) {
|
|
|
- const currentTimeNum = ctime || (state.audiosInstance.audio as HTMLAudioElement).currentTime
|
|
|
+ let currentTimeNum = ctime || (state.audiosInstance.audio as HTMLAudioElement).currentTime
|
|
|
+ // 如果是评测状态,当前时间取app返回的进度
|
|
|
+ if (state.evaluatingStatus) {
|
|
|
+ currentTimeNum = ctime ? ctime : 0
|
|
|
+ }
|
|
|
try {
|
|
|
metronomeData?.metro?.sound(currentTimeNum);
|
|
|
} catch (error) {}
|
|
|
|
|
|
const index = getIndex(detailState.times, currentTimeNum)
|
|
|
// 监听app返回的ctime
|
|
|
- // console.log(777777777,index,ctime)
|
|
|
+ // console.log(777777777,index,ctime,state.audiosInstance.audio.currentTime)
|
|
|
+ // if (state.evaluatingStatus) {
|
|
|
+ // console.log('评测模式','app返回的播放进度',ctime)
|
|
|
+ // } else {
|
|
|
+ // console.log('练习模式','h5播放器的播放进度',state.audiosInstance.audio.currentTime)
|
|
|
+ // }
|
|
|
dynamicShowPlaySpeed(index);
|
|
|
state.activeIndex = index
|
|
|
removeRepateBackground(index)
|
|
@@ -494,6 +517,8 @@ export const refreshPlayer = async (ctime?: number) => {
|
|
|
return false
|
|
|
}
|
|
|
const isNext = nextTime()
|
|
|
+ // console.log('选段123',detailState.section,detailState.sectionStatus)
|
|
|
+ // 选段播放结束
|
|
|
if (isNext) {
|
|
|
// console.log("isNext", detailState.section[1], detailState.section[1].endtime, currentTimeNum)
|
|
|
state.audiosInstance.setMute(true)
|
|
@@ -503,16 +528,17 @@ export const refreshPlayer = async (ctime?: number) => {
|
|
|
} else {
|
|
|
await state.audiosInstance.pause()
|
|
|
}
|
|
|
- // 如果是单元测验 和课后训练直接结束
|
|
|
- if (unitTestData.isSelectMeasureMode && state.evaluatingStatus){
|
|
|
- console.log(1)
|
|
|
+ // 如果是单元测验 和课后训练,或者是选段评测,选段播放结束 直接结束
|
|
|
+ if ((unitTestData.isSelectMeasureMode || detailState.section.length === 2) && state.evaluatingStatus){
|
|
|
+ console.log('选段播放结束')
|
|
|
event.emit('ended')
|
|
|
return
|
|
|
}
|
|
|
setSectionModeCurrentTime()
|
|
|
clearAccelerateRefreshPlayer()
|
|
|
setTimeout(() => {
|
|
|
- if (detailState.section.length){
|
|
|
+ // 开启了循环播放
|
|
|
+ if (detailState.section.length && SettingState.sett.loop){
|
|
|
setPlayState()
|
|
|
}
|
|
|
}, 1000)
|
|
@@ -572,6 +598,7 @@ export const resetPlayStatus = async (notStop?: boolean) => {
|
|
|
}
|
|
|
|
|
|
export const play = async () => {
|
|
|
+ console.log('播放执行')
|
|
|
// 评测是app播放,非h5播放
|
|
|
if (modelType.value === 'evaluation') return
|
|
|
if (state.isFirstPlay) {
|
|
@@ -593,6 +620,47 @@ export const play = async () => {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+const refreshNote = () => {
|
|
|
+ if (state.playState === 'play') {
|
|
|
+ const time = state.preAppAudioPlayTime / 1000;
|
|
|
+ state.currentTimeNum = time
|
|
|
+ refreshPlayer(time)
|
|
|
+ // console.log(66666663333)
|
|
|
+ refreshIndex(time)
|
|
|
+ // 播放到最后一秒,停止播放
|
|
|
+ if (state.appAudioTotalTime > 1000 && state.preAppAudioPlayTime >= state.appAudioTotalTime) {
|
|
|
+ console.log('播放结束123')
|
|
|
+ state.playState = 'pause'
|
|
|
+ state.playEndCallback.endEvaluat()
|
|
|
+ ended(new Event('ended'))
|
|
|
+ }
|
|
|
+ }
|
|
|
+ refreshView()
|
|
|
+}
|
|
|
+
|
|
|
+// 评测播放刷新音符进度
|
|
|
+export const setEvaluatingStep = () => {
|
|
|
+ // console.log('播放状态',state.playState)
|
|
|
+ if (state.playState !== "play") {
|
|
|
+ console.log("暂停播放");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ let startTime = Date.now();
|
|
|
+ requestAnimationFrame(() => {
|
|
|
+ const endTime = Date.now();
|
|
|
+ // 渲染时间大于16.6,就会让页面卡顿, 如果渲染时间大与16.6就下一个渲染帧去计算
|
|
|
+ if (endTime - startTime < 16.7) {
|
|
|
+ refreshNote()
|
|
|
+ setEvaluatingStep()
|
|
|
+ } else {
|
|
|
+ setTimeout(() => {
|
|
|
+ refreshNote()
|
|
|
+ setEvaluatingStep()
|
|
|
+ }, 16.7);
|
|
|
+ }
|
|
|
+ });
|
|
|
+};
|
|
|
+
|
|
|
const setDelayTime = async (time: number) => {
|
|
|
return new Promise((resolve) => {
|
|
|
setTimeout(() => {
|
|
@@ -629,12 +697,13 @@ export const playing = () => {
|
|
|
state.loading = false
|
|
|
}
|
|
|
|
|
|
-export const ended = debounce(async (evt: Event) => {
|
|
|
+export const ended = debounce(async (evt: Event, flag?: string) => {
|
|
|
resetPlayStatus()
|
|
|
detailState.fixedKey = 0
|
|
|
+ // console.log('需要重播',flag)
|
|
|
if (!state.evaluatingStatus) {
|
|
|
refreshPlayer(0)
|
|
|
- if (SettingState.sett.loop) {
|
|
|
+ if (SettingState.sett.loop || (flag && flag === 'isRePlay')) {
|
|
|
await setPlayState()
|
|
|
}
|
|
|
}
|
|
@@ -684,6 +753,7 @@ export const sectionChange = () => {
|
|
|
if (!detailState.sectionStatus) {
|
|
|
setCurrentTime(0)
|
|
|
detailState.fixedKey = 0
|
|
|
+ resetBaseRate();
|
|
|
}
|
|
|
if (detailState.sectionStatus && detailState.section.length != 2) {
|
|
|
resetCursor()
|
|
@@ -857,40 +927,51 @@ export const setTick = (stop: () => void, speed?: number) => {
|
|
|
numerator = state.osmd.numerator
|
|
|
denominator = state.osmd.denominator
|
|
|
}
|
|
|
- if (detailState.activeDetail.isAppPlay) {
|
|
|
- state.ticking = true
|
|
|
- postMessage(
|
|
|
- {
|
|
|
- api: 'cloudMetronome',
|
|
|
- content: {
|
|
|
- // 少量情况下需要重复
|
|
|
- repeat: numerator === 2 ? 2 : 1,
|
|
|
- denominator,
|
|
|
- numerator,
|
|
|
- },
|
|
|
- },
|
|
|
- (res) => {
|
|
|
- state.ticking = false
|
|
|
- if (res?.content.status === 'finish') {
|
|
|
- mixStop()
|
|
|
- } else if (res?.content.status === 'cancel') {
|
|
|
- event.emit('tickDestroy')
|
|
|
- }
|
|
|
- }
|
|
|
- )
|
|
|
- } else {
|
|
|
- const activeTickRepeat = numerator === 2 ? 2 : 1
|
|
|
- detailState.activeTickRepeat = activeTickRepeat
|
|
|
- console.log('ticking')
|
|
|
- state.tickPlayer = new TickPlayer(numerator, (speed || state.speed) / 90)
|
|
|
- state.tickPlayer?.start(numerator, (speed || state.speed) / 90, activeTickRepeat)
|
|
|
- state.tickPlayer?.event.off('tick', setActiveKey)
|
|
|
- state.tickPlayer?.event.off('stop', mixStop)
|
|
|
- state.tickPlayer?.event.off('destroy', onTickDestroy)
|
|
|
- state.tickPlayer?.event.on('tick', setActiveKey)
|
|
|
- state.tickPlayer?.event.on('stop', mixStop)
|
|
|
- state.tickPlayer?.event.on('destroy', onTickDestroy)
|
|
|
- }
|
|
|
+ // if (detailState.activeDetail.isAppPlay) {
|
|
|
+ // state.ticking = true
|
|
|
+ // postMessage(
|
|
|
+ // {
|
|
|
+ // api: 'cloudMetronome',
|
|
|
+ // content: {
|
|
|
+ // // 少量情况下需要重复
|
|
|
+ // repeat: numerator === 2 ? 2 : 1,
|
|
|
+ // denominator,
|
|
|
+ // numerator,
|
|
|
+ // },
|
|
|
+ // },
|
|
|
+ // (res) => {
|
|
|
+ // state.ticking = false
|
|
|
+ // if (res?.content.status === 'finish') {
|
|
|
+ // mixStop()
|
|
|
+ // } else if (res?.content.status === 'cancel') {
|
|
|
+ // event.emit('tickDestroy')
|
|
|
+ // }
|
|
|
+ // }
|
|
|
+ // )
|
|
|
+ // } else {
|
|
|
+ // const activeTickRepeat = numerator === 2 ? 2 : 1
|
|
|
+ // detailState.activeTickRepeat = activeTickRepeat
|
|
|
+ // console.log('ticking')
|
|
|
+ // state.tickPlayer = new TickPlayer(numerator, (speed || state.speed) / 90)
|
|
|
+ // state.tickPlayer?.start(numerator, (speed || state.speed) / 90, activeTickRepeat)
|
|
|
+ // state.tickPlayer?.event.off('tick', setActiveKey)
|
|
|
+ // state.tickPlayer?.event.off('stop', mixStop)
|
|
|
+ // state.tickPlayer?.event.off('destroy', onTickDestroy)
|
|
|
+ // state.tickPlayer?.event.on('tick', setActiveKey)
|
|
|
+ // state.tickPlayer?.event.on('stop', mixStop)
|
|
|
+ // state.tickPlayer?.event.on('destroy', onTickDestroy)
|
|
|
+ // }
|
|
|
+ const activeTickRepeat = numerator === 2 ? 2 : 1
|
|
|
+ detailState.activeTickRepeat = activeTickRepeat
|
|
|
+ console.log('ticking')
|
|
|
+ state.tickPlayer = new TickPlayer(numerator, (speed || state.speed) / 90)
|
|
|
+ state.tickPlayer?.start(numerator, (speed || state.speed) / 90, activeTickRepeat)
|
|
|
+ state.tickPlayer?.event.off('tick', setActiveKey)
|
|
|
+ state.tickPlayer?.event.off('stop', mixStop)
|
|
|
+ state.tickPlayer?.event.off('destroy', onTickDestroy)
|
|
|
+ state.tickPlayer?.event.on('tick', setActiveKey)
|
|
|
+ state.tickPlayer?.event.on('stop', mixStop)
|
|
|
+ state.tickPlayer?.event.on('destroy', onTickDestroy)
|
|
|
} else {
|
|
|
mixStop()
|
|
|
}
|
|
@@ -1043,23 +1124,34 @@ export const setAudioInit = () => {
|
|
|
})
|
|
|
// 监听评测曲谱音频播放进度,返回
|
|
|
listenerMessage("playProgress", (res) => {
|
|
|
- const time = res?.content.currentTime / 1000
|
|
|
- requestAnimationFrame(async () => {
|
|
|
- if (state.playState === 'play') {
|
|
|
- state.currentTimeNum = time
|
|
|
- refreshPlayer(time)
|
|
|
- // console.log(66666663333)
|
|
|
- refreshIndex(time)
|
|
|
- // 播放到最后一秒,停止播放
|
|
|
- if (res?.content?.totalDuration > 1000 && res?.content?.currentTime >= res?.content?.totalDuration) {
|
|
|
- console.log('播放结束123')
|
|
|
- state.playState = 'pause'
|
|
|
- state.playEndCallback.endEvaluat()
|
|
|
- ended(new Event('ended'))
|
|
|
- }
|
|
|
+ if (state.playState === 'play') {
|
|
|
+ const time = res?.content.currentTime / 1000
|
|
|
+ const diffTime = res?.content?.currentTime - state.preAppAudioPlayTime;
|
|
|
+
|
|
|
+ // console.log('app返回的mp3进度',time)
|
|
|
+ if (diffTime < 0) {
|
|
|
+ console.log('进度返回异常','本次时间比上次慢',diffTime,'当前播放时间:',res?.content?.currentTime)
|
|
|
+ return
|
|
|
}
|
|
|
- refreshView()
|
|
|
- })
|
|
|
+ state.preAppAudioPlayTime = res?.content?.currentTime
|
|
|
+ state.appAudioTotalTime = res?.content?.totalDuration
|
|
|
+ // requestAnimationFrame(async () => {
|
|
|
+ // if (state.playState === 'play') {
|
|
|
+ // state.currentTimeNum = time
|
|
|
+ // refreshPlayer(time)
|
|
|
+ // // console.log(66666663333)
|
|
|
+ // refreshIndex(time)
|
|
|
+ // // 播放到最后一秒,停止播放
|
|
|
+ // if (res?.content?.totalDuration > 1000 && res?.content?.currentTime >= res?.content?.totalDuration) {
|
|
|
+ // console.log('播放结束123')
|
|
|
+ // state.playState = 'pause'
|
|
|
+ // state.playEndCallback.endEvaluat()
|
|
|
+ // ended(new Event('ended'))
|
|
|
+ // }
|
|
|
+ // }
|
|
|
+ // refreshView()
|
|
|
+ // })
|
|
|
+ }
|
|
|
});
|
|
|
state.audiosInstance.event.on('timeupdate', () => {
|
|
|
state.currentTimeNum = state.audiosInstance.currentTime
|
|
@@ -1107,8 +1199,8 @@ export const noteClick = (evt: MouseEvent) => {
|
|
|
console.log('点击音符',activeNote)
|
|
|
if (activeNote) {
|
|
|
const time = activeNote.sourceStartTime || activeNote.time
|
|
|
- // 点击音符,动态设置右上角的速度
|
|
|
- if (activeNote.measureSpeed) {
|
|
|
+ // 点击音符,动态设置右上角的速度,非选段模式
|
|
|
+ if (activeNote.measureSpeed && detailState.section.length < 2) {
|
|
|
state.speed = Math.floor(state.basePlayRate * activeNote.measureSpeed)
|
|
|
state.playIngSpeed = state.speed
|
|
|
}
|