1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081 |
- /**
- * 播放过程中必要的context,效果与state一致仅用于操作,但是包含方法,好处是可以在任意地方调用,操作播放状态
- */
- import { Toast } from 'vant'
- import { reactive, watchEffect } from 'vue'
- import store from 'store'
- import { constant, throttle, debounce } from 'lodash'
- import {
- getActtiveNoteByTimes,
- getDuration,
- getIndex,
- getNoteBySlursStart,
- setStepIndex,
- getSlursNote,
- getVoicePartInfo,
- } from './helpers'
- import SectionHint from '/src/helpers/section-hint'
- import { browser, formatTime, getPlatform, getRequestHostname } from '/src/helpers/utils'
- import request from '/src/helpers/request'
- // import * as Tone from 'tone'
- import router from '/src/router'
- import appState from '/src/state'
- import detailState from './state'
- import SettingState from '/src/pages/detail/setting-state'
- // import fixtimeRela from '/src/constant/fixtime'
- import TickPlayer, { getTickTime } from '/src/components/tick/player'
- // import { tickByNumerator } from '/src/components/tick/constant'
- import { postMessage, listenerMessage, promisefiyPostMessage } from '/src/helpers/native-message'
- import EventEmitter from 'eventemitter3'
- import { useClientType, useOriginSearch } from '/src/subpages/colexiu/uses'
- import { evaluatPlayerStop } from '/src/subpages/colexiu/buttons/evaluating'
- export const event = new EventEmitter()
- const browserInfo = browser()
- const initBehaviorId = '' + new Date().valueOf()
- const getLinkId = (): string => {
- const seearchid = useOriginSearch().id as string
- return location.hash.split('?')[0].split('/').pop() || seearchid || ''
- }
- export const getFixtimeRelaVal = () => {
- const route: any = router.currentRoute.value
- const linkId = location.hash.split('?')[0].split('/').pop()
- return 0 //(fixtimeRela as any)[(route.params.id || linkId)] || 0
- }
- export const getFixTime = (speed: number) => {
- const duration: any = getDuration(state.osmd)
- let numerator = duration.numerator || 0
- let denominator = duration.denominator || 4
- if (detailState.repeatedBeats) {
- // 音频制作问题仅2拍不重复
- numerator = numerator === 2 ? 4 : numerator
- }
- // 音频制作问题仅2拍不重复
- // numerator = numerator === 2 ? 4 : numerator
- const time = !detailState.needTick && !detailState.skipTick ? ((denominator * 60) / speed / denominator) * numerator : 0//5 + getFixtimeRelaVal()
- return time
- }
- let prevIndex: number = 0
- export type IPlayState = 'init' | 'play' | 'pause' | 'suspend'
- export type IMode = 'background' | 'music'
- export type ISonges = {
- background?: string
- music?: string
- }
- const state = reactive({
- /** 曲目信息 */
- songs: {} as ISonges,
- /** 播放状态 */
- playState: 'init' as IPlayState,
- /** 当前播放背景 */
- sectionHint: new SectionHint(),
- /** 音频播放器实例 */
- audiosInstance: null as any,
- /** 原声伴奏 */
- mode: 'music' as IMode,
- /** 是否是第一次播放 */
- isFirstPlay: true,
- metro: null as any,
- metroing: false,
- /** 时长 */
- duration: '0:00',
- durationNum: 0,
- /** 当前时间 */
- currentTime: '0:00',
- currentTimeNum: 0,
- loading: false,
- /** 速度 */
- speed: 90,
- browser: browser(),
- /** 调速是否可见 */
- speedShow: false,
- /** 播放进度进度是否可见 */
- progressShow: false,
- touched: false,
- /** opendisplaymusicdisplay 实例 */
- osmd: null as any,
- /** 节拍器实例 */
- tickPlayer: null as any,
- /** 评测状态 */
- evaluatingStatus: false,
- /** 评测提示 */
- evaluatingTips: false,
- clickTime: 0,
- evaluatingFixTime: 0,
- /** 摄像头状态 */
- cameraStatus: false,
- /** 录制状态 */
- captureStatus: false,
- ticking: false,
- /** 第几分轨 */
- partIndex: 0,
- /** 当前音符index */
- activeIndex: 0
- })
- const syncStepIndex = (i: number) => {
- // console.log("🚀 ~ i", i)
-
- if (state.osmd.hidden !== false) {
- state.osmd.cursor.show()
- }
- prevIndex = i
- setStepIndex(state.osmd, i)
- refreshIndex(detailState.times[i]?.time)
- }
- watchEffect(() => {
- detailState.maskStatus = state.playState === 'play'
- })
- const syncPlayState = async () => {
- if (detailState.activeDetail.isAppPlay) {
- const cloudGetMediaStatus = await promisefiyPostMessage({
- api: 'cloudGetMediaStatus',
- })
- const status = cloudGetMediaStatus?.content.status
- state.playState = status
- } else {
- state.playState = state.audiosInstance.getStatus()
- }
- }
- export default state
- export const setCurrentTime = (time: number) => {
- console.log('setCurrentTime', time)
- const fixt = time // - 5
- // console.log('set', fixt)
- detailState.fixedKey = 0
- state.currentTimeNum = fixt
- state.currentTime = formatTime(fixt)
- if (detailState.activeDetail.isAppPlay) {
- promisefiyPostMessage({
- api: 'cloudSetCurrentTime',
- content: {
- currentTime: time * 1000,
- songID: detailState.activeDetail.examSongId,
- },
- })
- } else {
- state.audiosInstance.setCurrentTime(fixt)
- }
- refreshView()
- syncPlayState()
- const index = getIndex(detailState.times, state.currentTimeNum)
- syncStepIndex(index)
- // changeMode(state.mode)
- }
- export const onTimeChanged = (num: number) => {
- const time = Math.min(num, state.durationNum)
- const index = getIndex(detailState.times, state.currentTimeNum)
- setCurrentTime(time)
- syncStepIndex(index)
- // console.log('onTimeChanged', time)
- // changeMode(state.mode)
- }
- /** 获取当前MidiId */
- export const getActiveMidiId = () => {
- return state.osmd?.sheet?.instruments?.[0]?.subInstruments?.[0]?.midiInstrumentID ?? 0
- }
- /**
- * 修改原音或伴奏
- * @param val IMode
- */
- export const changeMode = async (val: IMode) => {
- const cm: IMode = val === 'background' ? 'music' : 'background'
- console.log(!state.songs[val], val, cm)
- if (detailState.activeDetail.isAppPlay) {
- const data = new Map()
- for (const name of detailState.partListNames) {
- data.set(name, 60)
- }
- for (const name of getVoicePartInfo().partListNames) {
- data.set(name, cm === 'background' ? 100 : 0)
- }
- promisefiyPostMessage({
- api: 'cloudVolume',
- content: {
- activeMidiId: getActiveMidiId(),
- activeMidiVolume: cm === 'background' ? 100 : 0,
- parts: Array.from(data.keys()).map((item) => ({
- name: item,
- volume: data.get(item),
- })),
- },
- })
- // state.mode = val
- // promisefiyPostMessage({
- // api: 'cloudSwitch',
- // content: {
- // songID: detailState.activeDetail.examSongId,
- // parts: cm === 'background' ? [] : getVoicePartInfo().partListNames,
- // }
- // })
- }
- // if (!state.songs[val]) {
- // return
- // }
- state.mode = val
- state.audiosInstance?.setMute(true, state.songs[cm])
- state.audiosInstance?.setMute(false, state.songs[val])
- }
- export const changeAllMode = () => {
- if (detailState.activeDetail?.isAppPlay) {
- const data = new Map()
- for (const name of detailState.partListNames) {
- data.set(name, 1)
- }
- promisefiyPostMessage({
- api: 'cloudVolume',
- content: {
- activeMidiId: getActiveMidiId(),
- activeMidiVolume: 100,
- parts: Array.from(data.keys()).map((item) => ({
- name: item,
- volume: data.get(item),
- })),
- },
- })
- } else {
- state.mode = 'background'
- state.audiosInstance?.setMute(true)
- }
- }
- export const changeSpeed = (speed: number, isSave: boolean = true) => {
- // console.log(speed)
- // const route: any = router.currentRoute.value
- const speeds = store.get('speeds') || {}
- if (isSave){
- speeds[getLinkId()] = speed
- store.set('speeds', speeds)
- }
- state.speed = speed
- if (!detailState.activeDetail) return
- state.audiosInstance?.setSpeed(speed / detailState.baseSpeed)
- promisefiyPostMessage({
- api: 'cloudChangeSpeed',
- content: {
- speed: speed,
- originalSpeed: detailState.activeDetail.originalSpeed,
- songID: detailState.activeDetail.examSongId,
- },
- })
- // changeMode(state.mode)
- if (state.playState === 'play') {
- syncStepIndex(getIndex(detailState.times, state.currentTimeNum))
- }
- }
- let nextLook: boolean = false
- let syncTimed: boolean = false
- export const resetCursor = () => {
- if (state.osmd) {
- if(state.osmd.product){
- state.osmd.cursor.setPosition({...detailState.times[0].cursorBox})
- } else {
- state.osmd.cursor.reset()
- }
- state.osmd.cursor.hide()
- detailState.fixedKey = 0
- }
- }
- export const refreshIndexBase = (index: number) => {
- if (index < 0) return
- const { osmd }: any = state
- if (osmd) {
- if (detailState.times[index]) {
- if (!detailState.sectionStatus) {
- state.sectionHint.show()
- }
- if (detailState.times[index] && detailState.times[index].noteElement) {
- state.sectionHint.showForElement(detailState.times[index])
- }
- if (!osmd.product){
- if (osmd.cursor.hidden !== false) {
- osmd.cursor.reset()
- osmd.cursor.show()
- detailState.fixedKey = 0
- }
- }
-
- if (prevIndex !== index) {
- setStepIndex(state.osmd, detailState.times[index].i, prevIndex)
- prevIndex = index
- }
- detailState.fixedKey = detailState.times[index].realKey
- detailState.activeNote = detailState.times[index]
- }
- }
- }
- export const refreshIndex = (ctime?: number) => {
- const { osmd }: any = state
- if (osmd && (ctime || state.audiosInstance.audio)) {
- const currentTimeNum = ctime || (state.audiosInstance.audio as HTMLAudioElement).currentTime
- const index = getIndex(detailState.times, currentTimeNum)
- state.activeIndex = index
- removeRepateBackground(index)
- // console.log(currentTimeNum, index, detailState.times[detailState.times.length - 1]?.endtime)
- const lastNote = detailState.times[detailState.times.length - 1]
- const endtime = lastNote?.sourceEndTime || lastNote?.endtime
- if (currentTimeNum > endtime) {
- state.osmd.cursor.hide()
- state.sectionHint.destroy()
- } else {
- if (detailState.times[index]) {
- refreshIndexBase(index)
- }
- }
- }
- }
- /** 重复中移除重复的背景 */
- export const removeRepateBackground = (index: number) => {
- if (state.evaluatingStatus && index) {
- const activeNote = detailState.times[index]
- const note = detailState.times[index + 1] || activeNote
- const number = note?.noteElement?.sourceMeasure?.measureListIndex
- // 0 比较特殊重置等操作会导致误操作所以跳过第0个
- if (note && detailState.evaluatings[number] && index > 0) {
- detailState.evaluatings = {
- ...detailState.evaluatings,
- [number]: undefined,
- }
- }
- }
- }
- /**
- * 刷新播放的状态
- * @param ctime 当前时间
- * @returns
- */
- export const refreshPlayer = async (ctime?: number) => {
- // if (!state.durationNum) {
- // loadedmetadata()
- // }
- // const status: IPlayState = state.audiosInstance.getStatus()
- const { osmd }: any = state
- if (osmd && (ctime || state.audiosInstance.audio)) {
- // state.playState = status
- const currentTimeNum = ctime || (state.audiosInstance.audio as HTMLAudioElement).currentTime
- // console.log('refreshPlayer', currentTimeNum)
- const mintime = 0 //detailState.times[0].time
- if (currentTimeNum + 1 < mintime) {
- setCurrentTime(mintime)
- return
- } else {
- syncTimed = false
- }
- const nextTime = () => {
- if (detailState.sectionStatus && detailState.section.length === 2) {
- // console.log("state.currentTimeNum >= detailState.section[0].time", state.currentTimeNum, detailState.section[0].time)
- if (currentTimeNum >= detailState.section[0].time) {
- detailState.sectionFlash = false
- }
- const nextNote = detailState.times[detailState.section[1].i + 1]
- const time = nextNote
- ? nextNote.halfTone === 0
- ? detailState.section[1].endtime
- : nextNote.time
- : state.durationNum
- // console.table({
- // currentTimeNum,
- // isNext: (browserInfo.xiaomi ? 0.2 : 0.08) >= time,
- // time,
- // nextNote
- // })
- return currentTimeNum + (browserInfo.xiaomi ? 0.2 : 0.08) >= time
- }
- return false
- }
- const isNext = nextTime()
- if (isNext) {
- // console.log("isNext", detailState.section[1], detailState.section[1].endtime, currentTimeNum)
- state.audiosInstance.setMute(true)
- state.osmd.cursor.hide()
- // resetPlayStatus()
- if (detailState.activeDetail?.isAppPlay) {
- pause()
- } else {
- await state.audiosInstance.pause()
- }
- // setCurrentTime(detailState.section[0].sourceStartTime || detailState.section[0].time)
- setSectionModeCurrentTime()
- clearAccelerateRefreshPlayer()
- setTimeout(() => setPlayState(), 1000)
- state.loading = false
- return
- }
- // 当MIDI进度超过最后一个音符时间触发结束事件
- if(detailState.activeDetail?.isAppPlay && state.durationNum + 3 < currentTimeNum) {
- if (state.evaluatingStatus) {
- pause()
- event.emit('ended', new Event('ended'))
- } else {
- if (SettingState.sett.loop) {
- await pause()
- await setCurrentTime(0)
- await play()
- } else {
- pause()
- }
- }
- }
- }
- }
- /**
- * 重置播放状态
- * @param notStop 是否停止播放
- */
- export const resetPlayStatus = async (notStop?: boolean) => {
- try {
- prevIndex = 0
- state.osmd.cursor.reset()
- state.osmd.cursor.hide()
- detailState.fixedKey = 0
- detailState.sectionFlash = false
- if (state.sectionHint) {
- state.sectionHint.destroy()
- }
- if (!notStop) {
- if (detailState.activeDetail.isAppPlay) {
- await promisefiyPostMessage({
- api: 'cloudSuspend',
- content: {
- songID: detailState.activeDetail.examSongId,
- },
- })
- endCapture()
- } else {
- console.log('resetPlayStatus调用暂停')
- state.audiosInstance.pause()
- }
- }
- syncPlayState()
- } catch (error) {
- console.log('resetPlayStatus错误', error)
- }
- }
- export const play = async () => {
- if (state.isFirstPlay) {
- resetPlayStatus()
- detailState.fixedKey = 0
- }
- if (detailState.activeDetail.isAppPlay) {
- await syncPlayState()
- promisefiyPostMessage({
- api: 'cloudSuspend',
- content: {
- songID: detailState.activeDetail.examSongId,
- },
- })
- startCapture()
- } else {
- state.playState = state.audiosInstance.getStatus()
- clearAccelerateRefreshPlayer()
- accelerateRefreshPlayer()
- startCapture()
- }
- }
- const setDelayTime = async (time: number) => {
- return new Promise((resolve) => {
- setTimeout(() => {
- resolve(time)
- }, time)
- })
- }
- /**
- * 暂停播放
- */
- export const pause = async () => {
- if (detailState.sectionStatus) {
- state.osmd.cursor.hide()
- }
- if (detailState.activeDetail.isAppPlay) {
- await syncPlayState()
- await promisefiyPostMessage({
- api: 'cloudSuspend',
- })
- await setDelayTime(200)
- endCapture()
- } else {
- state.playState = state.audiosInstance.getStatus()
- clearAccelerateRefreshPlayer()
- state.audiosInstance.pause()
- setTimeout(() => {
- // 确保播放完毕,延迟200ms
- endCapture()
- }, 200)
- }
- }
- export const waiting = () => {
- state.loading = true
- }
- export const playing = () => {
- state.loading = false
- }
- export const ended = debounce(async (evt: Event) => {
- resetPlayStatus()
- detailState.fixedKey = 0
- if (!state.evaluatingStatus) {
- refreshPlayer(0)
- if (SettingState.sett.loop) {
- await setPlayState()
- }
- }
- setCurrentTime(0)
- event.emit('ended', evt)
- }, 300, {
- 'leading': true,
- 'trailing': false
- })
- let timer: any = null
- let now = 0
- let nowTime = 0
- let prevTime: number = 0
- const accelerateRefreshPlayer = () => {
- if (timer || !state.audiosInstance) {
- return
- }
- timer = setInterval(() => {
- requestAnimationFrame(() => {
- refreshPlayer()
- if (state.audiosInstance.getStatus() === 'play') {
- refreshIndex()
- }
- })
- }, 16.7)
- }
- const clearAccelerateRefreshPlayer = () => {
- clearInterval(timer)
- timer = null
- now = 0
- }
- /**
- * 选择段落
- */
- export const sectionChange = () => {
- detailState.sectionStatus = !detailState.sectionStatus
- clearAccelerateRefreshPlayer()
- resetPlayStatus()
- if (!detailState.sectionStatus) {
- setCurrentTime(0)
- detailState.fixedKey = 0
- }
- if (detailState.sectionStatus && detailState.section.length != 2) {
- resetCursor()
- }
- }
- export const clearSectionStatus = () => {
- detailState.section = []
- detailState.sectionBoundingBoxs = []
- detailState.sectionStatus = false
- }
- export const getFirsrNoteByMeasureListIndex = (index: number, tie = true) => {
- for (const note of detailState.times) {
- if (note?.noteElement?.sourceMeasure?.measureListIndex === index) {
- let noteTies: any = null
- for (const item of note.measures) {
- if (getSlursNote(item)) {
- noteTies = getSlursNote(item)
- }
- }
- if (noteTies) {
- if (noteTies.sourceMeasure?.measureListIndex !== index) {
- for (const n of detailState.times) {
- if (n.noteElement.NoteToGraphicalNoteObjectId === noteTies.NoteToGraphicalNoteObjectId) {
- return n
- }
- }
- }
- }
- return note
- }
- }
- return null
- }
- export const setSectionModeCurrentTime = () => {
- console.log(detailState.needTick, 'setSectionModeCurrentTime')
- if (detailState.needTick) {
- setCurrentTime(detailState.section[0].sourceStartTime || detailState.section[0].time)
- } else {
- const measureListIndex = detailState.section[0].noteElement?.sourceMeasure?.measureListIndex
- if (measureListIndex > 0) {
- setCurrentTime(getFirsrNoteByMeasureListIndex(measureListIndex - 1).time)
- detailState.sectionFlash = true
- } else {
- setCurrentTime(0)
- }
- }
- }
- export const setPlayerView = () => {
- console.log(detailState.sectionStatus, 'detailState.sectionStatus')
- console.log(detailState.needTick)
- if (detailState.sectionStatus) {
- syncStepIndex(getIndex(detailState.times, state.currentTimeNum))
- if (detailState.section.length === 2) {
- // setCurrentTime(detailState.section[0].sourceStartTime || detailState.section[0].time)
- setSectionModeCurrentTime()
- } else {
- detailState.section = []
- detailState.sectionBoundingBoxs = []
- detailState.sectionStatus = false
- Toast.clear()
- }
- }
- }
- const cloudToggleState = async () => {
- const cloudGetMediaStatus = await promisefiyPostMessage({
- api: 'cloudGetMediaStatus',
- })
- const status = cloudGetMediaStatus?.content.status
- if (status === 'init') {
- return
- }
- if (status === 'suspend') {
- await promisefiyPostMessage({
- api: 'cloudPlay',
- content: {
- songID: detailState.activeDetail.examSongId,
- startTime: state.currentTimeNum * 1000,
- originalSpeed: detailState.activeDetail.originalSpeed,
- speed: state.speed,
- hertz: 440//SettingState.sett.hertz,
- },
- })
- startCapture()
- } else {
- await promisefiyPostMessage({
- api: 'cloudSuspend',
- })
- endCapture()
- }
- const cloudGetMediaStatused = await promisefiyPostMessage({
- api: 'cloudGetMediaStatus',
- })
- state.playState = cloudGetMediaStatused?.content.status
- console.log(cloudGetMediaStatused, 'cloudGetMediaStatused')
- }
- export const toggleState = async (delay?: number) => {
- if (detailState.activeDetail.isAppPlay) {
- await cloudToggleState()
- } else {
- console.log(detailState.activeDetail)
- console.log('delay', delay)
- state.isFirstPlay = false
- setPlayerView()
- await state.audiosInstance.togglePlay(delay)
- if (!state.evaluatingStatus) {
- changeMode(state.mode)
- }
- state.playState = state.audiosInstance.getStatus()
- }
- }
- const setActiveKey = (index: number) => {
- detailState.activeTick = index
- }
- const setTickStop = () => {
- console.log('节拍器结束', new Date().getTime() - state.clickTime)
- detailState.activeTick = -1
- detailState.activeTickRepeat = 1
- toggleState(getTickTime(state.speed / detailState.baseSpeed))
- }
- let timeliner: any = -1
- export const startIntervalTimeline = (maxTime: number, end: () => void) => {
- const nowTimeline = new Date().getTime()
- let currenttTime = 0
- const throttleIndex = throttle(() => {
- if (currenttTime) {
- refreshView()
- }
- }, 1200)
- const start = () => {
- requestAnimationFrame(() => {
- currenttTime = (new Date().getTime() - nowTimeline) / 1000
- refreshIndex(currenttTime)
- if (maxTime && currenttTime >= maxTime) {
- clearIntervalTimeline()
- end()
- }
- throttleIndex()
- })
- }
- start()
- timeliner = setInterval(() => {
- start()
- }, 16.7)
- }
- export const clearIntervalTimeline = () => {
- clearInterval(timeliner)
- }
- const onTickDestroy = () => {
- event.emit('tickDestroy')
- }
- export const setTick = (stop: () => void, speed?: number) => {
- // 节拍时间是固定的无需调整
- console.log('ticking')
- const mixStop = () => {
- stop()
- event.emit('tickEnd')
- }
- if (detailState.needTick) {
- let { numerator, denominator } = getDuration(state.osmd)
- if (state.osmd.numerator && state.osmd.denominator){
- 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)
- }
- } else {
- mixStop()
- }
- }
- export const setPlayState = async () => {
- // console.log('click play', detailState.activeTick, state.audiosInstance.getStatus())
- if (detailState.activeTick > -1 || state.ticking) {
- return
- }
- await syncPlayState()
- console.table({
- playState: state.playState,
- currentTime: state.currentTimeNum,
- })
- if (state.playState !== 'pause' && state.playState !== 'suspend') {
- await toggleState()
- return
- }
- console.log('设置播放')
- setPlayerView()
- setTick(setTickStop)
- }
- export const stopTick = () => {
- if (state.tickPlayer) {
- state.tickPlayer.destroy()
- }
- event.emit('stopTick')
- detailState.activeTickRepeat = 1
- detailState.activeTick = -1
- }
- export const windowResize = () => {
- const index = getIndex(detailState.times, state.currentTimeNum)
- setTimeout(() => {
- state.sectionHint?.showForElement(detailState.times[index]?.noteElement)
- }, 200)
- }
- export const loadedmetadata = () => {
- state.duration = formatTime(state.audiosInstance.duration)
- state.durationNum = state.audiosInstance.duration
- }
- let prevDiff: number = 0
- let viewing: boolean = false
- export const refreshView = () => {
- let cursorEl : any = undefined
- let containerEl : any = undefined
- if (state?.osmd?.product){
- cursorEl = state.osmd.cursor.img
- containerEl = document.querySelector('#colexiu-detail-music-sheet')
- }
- const top = Math.max(parseFloat((cursorEl || state.osmd.cursor.cursorElement).style.top), 0)
- if (Math.abs(prevDiff - top) > 10 && !viewing) {
- viewing = true
- setTimeout(() => {
- viewing = false
- const scrollElement = containerEl ? containerEl :
- appState.clintNmae === 'colexiu'
- ? state.osmd.container.parentElement.parentElement
- : state.osmd.container.parentElement
- scrollElement.scrollTo({
- top: top,
- left: 0,
- behavior: 'smooth',
- })
- prevDiff = top
- }, 100)
- }
- }
- const updatePlayTime = async (time: number) => {
- const search = useOriginSearch()
- const behaviorId = sessionStorage.getItem('behaviorId') || search.behaviorId || initBehaviorId
- const prefix = getRequestHostname()
- const clientType = useClientType()
- if (!state.evaluatingStatus) {
- // 如果是后台不需要统计时长
- if (clientType === 'web') return
- try {
- const res = await request.post('/musicPracticeRecord/save', {
- prefix: prefix,
- requestType: 'json',
- data: {
- musicSheetId: getLinkId(),
- sysMusicScoreId: getLinkId(),
- feature: 'EVALUATION',
- playTime: time,
- deviceType: getPlatform(),
- behaviorId,
- },
- })
- event.emit('updatePlayTimeSuccess', res.data)
- } catch (error) {}
-
- }
- //课后训练
- if (search.lessonTrainingId) {
- try {
- console.log(prefix)
- const res = await request.post('/studentLessonTraining/lessonTrainingRecord', {
- prefix: prefix,
- requestType: 'json',
- data: {
- materialType: 'SONG',
- record: {
- clientType: (clientType as string)?.toLocaleUpperCase(),
- feature: search.feature,
- deviceType: browserInfo.android ? 'ANDROID' : browserInfo.isApp ? 'IOS' : 'WEB',
- behaviorId,
- playTime: time,
- musicSheetId: getLinkId(),
- },
- courseScheduleId: search.courseScheduleId,
- lessonTrainingId: search.lessonTrainingId,
- materialId: search.materialId,
- },
- })
- } catch (error) {}
- }
- }
- export const setAudioInit = () => {
- state.audiosInstance.event.on('loadedmetadata', loadedmetadata)
- state.audiosInstance.event.on('waiting', waiting)
- state.audiosInstance.event.on('playing', playing)
- state.audiosInstance.event.on('play', play, false)
- state.audiosInstance.event.on('pause', pause, false)
- state.audiosInstance.event.on('ended', ended, false)
- state.audiosInstance.event.on('updatePlayTime', updatePlayTime, false)
- listenerMessage('cloudplayed', async () => {
- await syncPlayState()
- state.currentTimeNum = 0
- state.currentTime = '00:00'
- state.audiosInstance.event.emit('ended', new Event('ended'))
- })
- listenerMessage('cloudTimeUpdae', (res) => {
- // console.log('cloudTimeUpdae', res?.content.currentTime)
- const time = res?.content.currentTime / 1000
- // requestAnimationFrame(async () => {
- // const cloudGetMediaStatus = await promisefiyPostMessage({
- // api: 'cloudGetMediaStatus',
- // content: {
- // songID: detailState.activeDetail.examSongId,
- // }
- // })
- // const status = cloudGetMediaStatus?.content.status
- if (state.playState === 'play') {
- state.currentTimeNum = time
- state.currentTime = formatTime(time)
- refreshPlayer(time)
- refreshIndex(time)
- }
- refreshView()
- // })
- })
- state.audiosInstance.event.on('timeupdate', () => {
- state.currentTimeNum = state.audiosInstance.currentTime
- state.currentTime = formatTime(state.audiosInstance.currentTime)
- requestAnimationFrame(() => {
- if (state.audiosInstance.getStatus() === 'play') {
- refreshPlayer()
- }
- refreshView()
- })
- })
- window.addEventListener('resize', windowResize)
- }
- export const back = () => {
- if (state.browser.isApp) {
- postMessage({
- api: 'back',
- })
- } else {
- // (this as any).$router.replace({
- // path: '/',
- // })
- }
- }
- export const setStepView = (activeNote: any, time?: number) => {
- prevIndex = Math.max(activeNote.i, 0)
- syncStepIndex(activeNote.i)
- if (time) {
- // console.log(time)
- refreshPlayer(time)
- }
- refreshView()
- }
- export const noteClick = (evt: MouseEvent) => {
- if (state.isFirstPlay) {
- Toast('开始播放后才能调整进度')
- return
- }
- let activeNote = getNoteBySlursStart(getActtiveNoteByTimes(evt))
- if (activeNote) {
- const time = activeNote.sourceStartTime || activeNote.time
- setCurrentTime(time)
- setStepView(activeNote.i, time)
- detailState.fixedKey = activeNote.realKey
- detailState.activeNote = activeNote
- }
- }
- let playStartTime: number = 0
- export const startCapture = async () => {
- if (detailState.activeDetail?.isAppPlay) {
- playStartTime = new Date().getTime()
- console.log('startCapture', playStartTime)
- }
- // console.log('startCapture:',SettingState.sett.camera, browserInfo.isApp, !state.captureStatus, state.evaluatingStatus, SettingState.eva.save)
- if (
- SettingState.sett.camera &&
- browserInfo.isApp &&
- !state.captureStatus &&
- state.evaluatingStatus &&
- SettingState.eva.save
- ) {
- state.captureStatus = true
- postMessage({
- api: 'startCapture',
- }, () => {
- postMessage({
- api: 'setCaptureMode',
- content: {
- mode: 'evaluating',
- },
- })
- })
- }
- }
- export const endCapture = async () => {
- if (detailState.activeDetail?.isAppPlay) {
- const playTime = new Date().getTime() - playStartTime
- if (playStartTime !== 0 && playTime > 0) {
- state.audiosInstance?.event.emit('updatePlayTime', playTime / 1000)
- playStartTime = 0
- }
- }
- if (browserInfo.isApp && state.evaluatingStatus && SettingState.sett.camera && state.captureStatus) {
- postMessage(
- {
- api: 'endCapture',
- },
- () => {
- state.captureStatus = false
- }
- )
- evaluatPlayerStop()
- }
- }
- export const setCaptureMode = async () => {
- if (browserInfo.isApp && SettingState.sett.camera) {
- postMessage({
- api: 'setCaptureMode',
- content: {
- mode: state.evaluatingStatus ? 'evaluating' : 'practice',
- },
- })
- }
- }
|