|
@@ -12,10 +12,22 @@ import state, { IPlayState, onEnded, onPlay } from "/src/state";
|
|
|
import { api_playProgress, api_cloudTimeUpdae, api_cloudplayed, api_remove_cloudplayed, api_remove_cloudTimeUpdae } from "/src/helpers/communication";
|
|
|
import { evaluatingData } from "/src/view/evaluating";
|
|
|
import { cloudToggleState } from "/src/helpers/midiPlay"
|
|
|
+import { metronomeData } from "../../helpers/metronome";
|
|
|
+import Crunker from "../../utils/crunker"
|
|
|
+const crunker = new Crunker()
|
|
|
+import tickWav from "/src/assets/tick.mp3";
|
|
|
+import tockWav from "/src/assets/tock.mp3";
|
|
|
+import Loading from "./loading"
|
|
|
|
|
|
export const audioData = reactive({
|
|
|
songEle: null as unknown as HTMLAudioElement,
|
|
|
backgroundEle: null as unknown as HTMLAudioElement,
|
|
|
+ songCollection: { // 音乐源合集 beatSongEle和bateBackgroundEle是带节拍的音乐源 评测模式的时候用
|
|
|
+ songEle: null as unknown as HTMLAudioElement,
|
|
|
+ backgroundEle: null as unknown as HTMLAudioElement,
|
|
|
+ beatSongEle: null as unknown as HTMLAudioElement,
|
|
|
+ bateBackgroundEle: null as unknown as HTMLAudioElement,
|
|
|
+ },
|
|
|
midiRender: false,
|
|
|
progress: 0, // midi播放进度(单位:秒)
|
|
|
duration: 0 // 音频总时长(单位:秒)
|
|
@@ -112,6 +124,37 @@ export const detectTheNumberOfSoundSources = () => {
|
|
|
return total;
|
|
|
};
|
|
|
|
|
|
+/** 切换节拍器音源 */
|
|
|
+export const changeSongSourceByBate = (isDisBate:boolean) => {
|
|
|
+ // isDisBate 为true 切换到不带节拍的,为false 切换到带节拍的
|
|
|
+ if(audioData.songCollection.songEle && audioData.songCollection.beatSongEle){
|
|
|
+ const songEleCurrentTime = audioData.songEle.currentTime
|
|
|
+ console.log("当前音乐时间:",songEleCurrentTime)
|
|
|
+ if(isDisBate){
|
|
|
+ audioData.songEle = audioData.songCollection.songEle
|
|
|
+ audioData.songEle.currentTime = songEleCurrentTime
|
|
|
+ if(audioData.songCollection.backgroundEle){
|
|
|
+ audioData.backgroundEle = audioData.songCollection.backgroundEle
|
|
|
+ audioData.backgroundEle.currentTime = songEleCurrentTime
|
|
|
+ }
|
|
|
+ }else{
|
|
|
+ audioData.songEle = audioData.songCollection.beatSongEle
|
|
|
+ audioData.songEle.currentTime = songEleCurrentTime
|
|
|
+ if(audioData.songCollection.bateBackgroundEle){
|
|
|
+ audioData.backgroundEle = audioData.songCollection.bateBackgroundEle
|
|
|
+ audioData.backgroundEle.currentTime = songEleCurrentTime
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // 设置静音与取消静音
|
|
|
+ if (state.playSource === "music") {
|
|
|
+ audioData.songEle && (audioData.songEle.muted = false);
|
|
|
+ audioData.backgroundEle && (audioData.backgroundEle.muted = true);
|
|
|
+ } else {
|
|
|
+ audioData.songEle && (audioData.songEle.muted = true);
|
|
|
+ audioData.backgroundEle && (audioData.backgroundEle.muted = false);
|
|
|
+ }
|
|
|
+}
|
|
|
export default defineComponent({
|
|
|
name: "audio-list",
|
|
|
setup() {
|
|
@@ -202,32 +245,89 @@ export default defineComponent({
|
|
|
onEnded();
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
- onMounted(() => {
|
|
|
+ // 合成节拍器音源
|
|
|
+ function loadMergeAudioBetas() {
|
|
|
+ console.time("音频加载时间")
|
|
|
+ const audioList = [state.music+'?v='+Date.now()]
|
|
|
+ if(state.accompany){ // 可能存在没有伴奏的音源
|
|
|
+ audioList.push(state.accompany+'?v='+Date.now())
|
|
|
+ }
|
|
|
+ return crunker.fetchAudio(tickWav, tockWav, ...audioList).then(([tickWavBuff,tockWavBuff,musicBuff,accompanyBuff])=>{
|
|
|
+ console.timeEnd("音频加载时间")
|
|
|
+ // 计算音频空白时间
|
|
|
+ const silenceDuration = crunker.calculateSilenceDuration(musicBuff)
|
|
|
+ const silenceBgDuration = accompanyBuff && crunker.calculateSilenceDuration(accompanyBuff)
|
|
|
+ console.log(`音频空白时间:${silenceDuration},${silenceBgDuration}`)
|
|
|
+ const beats:AudioBuffer[] = []
|
|
|
+ const beatsTime:number[] = []
|
|
|
+ const beatsBgTime:number[] = []
|
|
|
+ metronomeData.metroMeasure.map(Measures=>{
|
|
|
+ Measures.map((item:any)=>{
|
|
|
+ beats.push(item.index===0?tickWavBuff:tockWavBuff)
|
|
|
+ beatsTime.push(item.time + silenceDuration) // xml 计算的时候 加上空白的时间
|
|
|
+ accompanyBuff && beatsBgTime.push(item.time + silenceBgDuration) // xml 计算的时候 加上空白的时间
|
|
|
+ })
|
|
|
+ })
|
|
|
+ //合并
|
|
|
+ console.time("音频合并时间")
|
|
|
+ const musicBuffMeg = crunker.mergeAudioBuffers([musicBuff,...beats],[0,...beatsTime])
|
|
|
+ const accompanyBuffMeg = accompanyBuff && crunker.mergeAudioBuffers([accompanyBuff,...beats],[0,...beatsBgTime])
|
|
|
+ console.timeEnd("音频合并时间")
|
|
|
+ return [musicBuffMeg,accompanyBuffMeg]
|
|
|
+ }).then(([musicBuffMeg,accompanyBuffMeg])=>{
|
|
|
+ console.time("音频audioDom生成时间")
|
|
|
+ const musicAudio = crunker.exportAudioElement(musicBuffMeg)
|
|
|
+ const accompanyAudio = accompanyBuffMeg && crunker.exportAudioElement(accompanyBuffMeg)
|
|
|
+ console.timeEnd("音频audioDom生成时间")
|
|
|
+ return [musicAudio,accompanyAudio]
|
|
|
+ })
|
|
|
+ }
|
|
|
+ // 加载普通音源
|
|
|
+ function loadAudio(){
|
|
|
+ return Promise.all([createAudio(state.music), createAudio(state.accompany)])
|
|
|
+ }
|
|
|
+ onMounted(async () => {
|
|
|
if (state.playMode !== "MIDI") {
|
|
|
- Promise.all([createAudio(state.music), createAudio(state.accompany)]).then(
|
|
|
- ([music, accompany]) => {
|
|
|
- state.audioDone = true;
|
|
|
- // console.log(music, accompany);
|
|
|
- if (music) {
|
|
|
- audioData.songEle = music;
|
|
|
- }
|
|
|
- if (accompany) {
|
|
|
- audioData.backgroundEle = accompany;
|
|
|
- }
|
|
|
- if (audioData.songEle) {
|
|
|
- audioData.songEle.addEventListener("play", onPlay);
|
|
|
- audioData.songEle.addEventListener("ended", onEnded);
|
|
|
- accompany && (accompany.muted = true);
|
|
|
- } else if (audioData.backgroundEle) {
|
|
|
- audioData.backgroundEle.addEventListener("play", onPlay);
|
|
|
- audioData.backgroundEle.addEventListener("ended", onEnded);
|
|
|
- }
|
|
|
+ console.time("加载资源耗时")
|
|
|
+ // 不带节拍的音源
|
|
|
+ const [music, accompany] = await loadAudio()
|
|
|
+ try {
|
|
|
+ // 带节拍的音源
|
|
|
+ const [musicAudio,accompanyAudio] = await loadMergeAudioBetas()
|
|
|
+ console.log("音频合成成功66666666")
|
|
|
+ state.audioBetaDone = true;
|
|
|
+ if (musicAudio) {
|
|
|
+ musicAudio.addEventListener("play", onPlay);
|
|
|
+ musicAudio.addEventListener("ended", onEnded);
|
|
|
+ accompanyAudio && (accompanyAudio.muted = true);
|
|
|
+ } else if (accompanyAudio) {
|
|
|
+ accompanyAudio.addEventListener("play", onPlay);
|
|
|
+ accompanyAudio.addEventListener("ended", onEnded);
|
|
|
}
|
|
|
- );
|
|
|
-
|
|
|
+ Object.assign(audioData.songCollection,{
|
|
|
+ songEle:music,
|
|
|
+ backgroundEle:accompany,
|
|
|
+ beatSongEle:musicAudio,
|
|
|
+ bateBackgroundEle:accompanyAudio
|
|
|
+ })
|
|
|
+ } catch (err) {
|
|
|
+ console.log("音频合成失败7777777:",err)
|
|
|
+ }
|
|
|
+ state.audioDone = true;
|
|
|
+ audioData.backgroundEle = accompany!;
|
|
|
+ audioData.songEle = music!;
|
|
|
+ if (music) {
|
|
|
+ music.addEventListener("play", onPlay);
|
|
|
+ music.addEventListener("ended", onEnded);
|
|
|
+ accompany && (accompany.muted = true);
|
|
|
+ } else if (accompany) {
|
|
|
+ accompany.addEventListener("play", onPlay);
|
|
|
+ accompany.addEventListener("ended", onEnded);
|
|
|
+ }
|
|
|
+ console.timeEnd("加载资源耗时")
|
|
|
api_playProgress(progress);
|
|
|
} else {
|
|
|
+ state.audioDone = true;
|
|
|
const songEndTime = state.times[state.times.length - 1 || 0]?.endtime || 0
|
|
|
audioData.duration = songEndTime
|
|
|
// 监听midi播放进度
|
|
@@ -243,16 +343,19 @@ export default defineComponent({
|
|
|
|
|
|
// console.log(state.playMode, state.midiUrl);
|
|
|
return () => (
|
|
|
- <div class={styles.audioList}>
|
|
|
- {state.playMode === "MIDI" && state.speed != 0 && (
|
|
|
- <iframe
|
|
|
- style={{ display: "none" }}
|
|
|
- ref={midiRef}
|
|
|
- src={`/midi/index.html`}
|
|
|
- onLoad={handleLoad}
|
|
|
- />
|
|
|
- )}
|
|
|
- </div>
|
|
|
+ <>
|
|
|
+ <Loading/>
|
|
|
+ <div class={styles.audioList}>
|
|
|
+ {state.playMode === "MIDI" && state.speed != 0 && (
|
|
|
+ <iframe
|
|
|
+ style={{ display: "none" }}
|
|
|
+ ref={midiRef}
|
|
|
+ src={`/midi/index.html`}
|
|
|
+ onLoad={handleLoad}
|
|
|
+ />
|
|
|
+ )}
|
|
|
+ </div>
|
|
|
+ </>
|
|
|
);
|
|
|
},
|
|
|
});
|