import { reactive } from 'vue'; import tockAndTick from './tockAndTick.json'; import { Howl } from 'howler'; import { initSelectScorePart, setting } from './setting'; import { beatDesc } from './beat-desc'; const beatData = reactive({ list: [] as number[], len: 0, tickEnd: false, /** 节拍器时间 */ beatLengthInMilliseconds: 0, loopTime: 0, // 循环时长 state: '', source1: '' as any, source2: new Howl({ src: tockAndTick.tock }) as any, index: 0, show: false }); const handlePlay = (i: number, source: any, timer: any) => { let payBeatTime = new Date().getTime(); return new Promise(resolve => { if (beatData.tickEnd) { resolve(i); return; } let timeSppedEnum = 16.7; const proofTime = () => { if (setting.playState !== 'play') { return; } setTimeout(() => { const currentTime = new Date().getTime(); // 两次定时任务时间间隔 const diffTime = currentTime - payBeatTime; if (diffTime >= beatData.loopTime) { beatData.index++; if (timer.type === 'sound') { if (source) source.play(); } resolve(i); payBeatTime = currentTime; } else { if (Math.abs(diffTime - beatData.loopTime) <= timeSppedEnum) { // 为了处理最后循环时间,用循环耗时 for (let index = 0; index < 500000; index++) { let forTime = new Date().getTime(); if (Math.abs(forTime - payBeatTime) >= beatData.loopTime) { beatData.index++; if (timer.type === 'sound') { if (source) source.play(); } resolve(i); payBeatTime = forTime; break; } } } else { proofTime(); } } }, timeSppedEnum); }; proofTime(); }); }; /** 开始节拍器 */ export const handleStartBeat = async () => { beatData.show = true; beatData.tickEnd = false; beatData.index = 0; beatData.beatLengthInMilliseconds = (60 / setting.speed) * 1000; // let startTime = +new Date(); for (let i = 0; i < setting.scorePart.length; i++) { if (beatData.tickEnd) return false; for (let j = 0; j < setting.scorePart[i].length; j++) { if (beatData.tickEnd) return false; // 提前结束, 直接放回false const part = setting.scorePart[i][j]; const params = { ...part, ...beatDesc[part.index + 1] }; const single16th = beatData.beatLengthInMilliseconds; const source = beatData.source2; for (let g = 0; g < params.attribute.length; g++) { let time = 0; const attr = params.attribute[g]; // 计算每一拍需要的时长 // 四分音符 有延音 switch (attr.number) { case 4: if (attr.point) { time = single16th * 0.5 * 3; } else { time = single16th; } break; case 8: // 连音 if (params.liaison) { time = single16th * (1 / params.beatNum); } else if (attr.point) { time = single16th * 0.25 * 3; } else { time = single16th * 0.5; } break; case 16: if (params.liaison) { time = single16th * (1 / params.beatNum); } else { time = single16th * 0.25; } break; } await handlePlay(i, source, { time, type: attr.type }); beatData.loopTime = time; initSelectScorePart(i, j); } } } // console.log(+new Date() - startTime); beatData.show = false; handleStartBeat(); return true; }; /** 设置节拍器 * @param beatLengthInMilliseconds 节拍间隔时间 * @param beat 节拍数 */ export const handleInitBeat = ( beatLengthInMilliseconds: number, beat: number ) => { beatData.state = ''; beatData.beatLengthInMilliseconds = beatLengthInMilliseconds; beatData.loopTime = beatLengthInMilliseconds; beatData.len = beat; }; /** 节拍器暂停 */ export const hendleEndBeat = () => { beatData.tickEnd = true; initSelectScorePart(); };