Browse Source

feat: midi播放1.0

TIANYONG 1 year ago
parent
commit
0c95baf768

+ 82 - 6
src/helpers/midiPlay.tsx

@@ -1,11 +1,18 @@
+/**
+ * app播放midi
+ */
+
 import { ref } from 'vue'
 import { getDuration } from "/src/helpers/formateMusic";
-// import runtime, * as RuntimeUtils from '/src/pages/detail/runtime';
-import state from "/src/state";
+import state, { onPlay } from "/src/state";
 import { OpenSheetMusicDisplay } from "/osmd-extended/src";
-import { api_cloudDestroy, api_cloudDetail } from "/src/helpers/communication";
+import { api_cloudDestroy, api_cloudDetail, api_cloudVolume, api_cloudGetMediaStatus, 
+  api_cloudPlay, api_cloudSuspend,  } from "/src/helpers/communication";
+import { audioData } from "/src/view/audio-list"  
+
+export type IMode = 'background' | 'music'
 
-export const useMidi = (durationNum: number, midiUrl?: string) => {
+export const initMidi = (durationNum: number, midiUrl?: string) => {
   const initial = ref(false)
   if (midiUrl) {
     console.log('曲谱为midi,使用app播放')
@@ -29,12 +36,81 @@ export const useMidi = (durationNum: number, midiUrl?: string) => {
       state.midiPlayIniting = false
       initial.value = false
       if (midiUrl) {
-        //RuntimeUtils.changeMode('music')
+        changeMode('music')
       }
     })
-    //runtime.durationNum = durationNum
+    state.durationNum = durationNum
   }
   return {
     initial,
   }
 }
+
+/** 获取当前MidiId */
+export const getActiveMidiId = () => {
+  return state.osmd?.sheet?.instruments?.[0]?.subInstruments?.[0]?.midiInstrumentID ?? 0
+}
+
+/**
+ * 修改原音或伴奏
+ * @param val IMode
+ */
+export const changeMode = async (val: IMode, type?: string | undefined) => {
+  const cm: IMode = val === 'background' ? 'music' : 'background'
+  console.log(!state.songs[val], val, cm)
+  if (state.isAppPlay) {
+    const data = new Map()
+    for (const name of state.partListNames) {
+      data.set(name, 60)
+    }
+    // for (const name of getVoicePartInfo().partListNames) {
+    //   data.set(name, cm === 'background' ? 100 : 0)
+    // }
+    api_cloudVolume({
+      activeMidiId: getActiveMidiId(),
+      activeMidiVolume: cm === 'background' ? 100 : 0,
+      parts: Array.from(data.keys()).map((item) => ({
+        name: item,
+        volume: data.get(item),
+      })),
+    })
+  }
+  state.playSource = val
+  if (type === 'all') {
+    state.audiosInstance?.setMute(true, state.songs[cm])
+    state.audiosInstance?.setMute(true, state.songs[val])
+  } else {
+    state.audiosInstance?.setMute(true, state.songs[cm])
+    state.audiosInstance?.setMute(false, state.songs[val])
+  }
+}
+
+/**
+ * 切换midi播放状态
+ */
+export const cloudToggleState = async () => {
+  const cloudGetMediaStatus = await api_cloudGetMediaStatus();
+  const status = cloudGetMediaStatus?.content.status
+  if (status === 'init') {
+    return
+  }
+  if (status === 'suspend') {
+    await api_cloudPlay({
+      songID: state.examSongId,
+      startTime: audioData.progress * 1000,
+      originalSpeed: state.originSpeed, // midi初始速度
+      speed: state.speed, // 实际速度
+      hertz: 440, //SettingState.sett.hertz,
+    })
+    // startCapture()
+    onPlay()
+  } else {
+    await api_cloudSuspend({
+      songID: state.examSongId,
+    })
+    // endCapture()
+  }
+  const cloudGetMediaStatused = await api_cloudGetMediaStatus()
+  state.playState = cloudGetMediaStatused?.content.status
+  console.log(cloudGetMediaStatused, 'cloudGetMediaStatused')
+}

+ 4 - 1
src/page-instrument/header-top/index.tsx

@@ -192,7 +192,8 @@ export default defineComponent({
       if (headTopData.modeType !== "show") return { display: false, disabled: false };
       // 评测模式 不显示,跟练模式 不显示
       if (["evaluating", "follow"].includes(state.modeType)) return { display: false, disabled: true };
-
+      // midi音频未初始化完成不可点击
+      if (state.isAppPlay && state.midiPlayIniting) return { display: true, disabled: true };
       return {
         display: true,
         disabled: false,
@@ -209,6 +210,8 @@ export default defineComponent({
       if (state.playState === "play") return { display: false, disabled: true };
       // 播放进度为0 不显示
       const currentTime = getAudioCurrentTime();
+      // midi音频未初始化完成不可点击
+      if (state.isAppPlay && state.midiPlayIniting) return { display: false, disabled: true };
       if (!currentTime) return { display: false, disabled: true };
 
       return {

+ 7 - 0
src/page-instrument/view-detail/index.tsx

@@ -29,6 +29,7 @@ import { recalculateNoteData } from "/src/view/selection";
 import ToggleMusicSheet from "/src/view/plugins/toggleMusicSheet";
 import { setCustomGradual, setCustomNoteRealValue } from "/src/helpers/customMusicScore"
 import { usePageVisibility } from "@vant/use";
+import { initMidi } from "/src/helpers/midiPlay"
 
 /**
  * 特殊教材分类id
@@ -154,6 +155,12 @@ export default defineComponent({
       state.times = resetFrequency(state.times);
       state.times = setNoteHalfTone(state.times);
       console.log("🚀 ~ state.times:", state.times, state.subjectId, state);
+      // 初始化midi音频信息
+      const songEndTime = state.times[state.times.length - 1 || 0]?.endtime || 0
+      if (state.isAppPlay) {
+        const durationNum = songEndTime
+        initMidi(durationNum, state.midiUrl)
+      }
       state.measureTime = state.times[0]?.measureLength || 0
       try {
         metronomeData.metro = new Metronome();

+ 24 - 3
src/state.ts

@@ -9,7 +9,7 @@ import { handleStartTick } from "./view/tick";
 import { audioListStart, getAudioCurrentTime, getAudioDuration, setAudioCurrentTime, setAudioPlaybackRate } from "./view/audio-list";
 import { toggleFollow } from "./view/follow-practice";
 import { browser, setStorageSpeed, setGlobalData } from "./utils";
-import { api_createMusicPlayer } from "./helpers/communication";
+import { api_cloudGetMediaStatus, api_createMusicPlayer } from "./helpers/communication";
 import { verifyCanRepeat, getDuration } from "./helpers/formateMusic";
 import { getMusicSheetDetail } from "./utils/baseApi"
 import { getQuery } from "/src/utils/queryString";
@@ -40,6 +40,11 @@ export enum IPlatform {
   PC = "PC",
 }
 
+export type ISonges = {
+  background?: string
+  music?: string
+}
+
 /**
  * 特殊教材分类id
  */
@@ -364,7 +369,7 @@ const state = reactive({
   },
   /** 后台设置的基准评测频率 */
   baseFrequency: 440,
-  /** 节拍器的时间 */
+  /** mp3节拍器的时间,统计拍数、速度计算得出 */
   fixtime: 0,
   /** 指法信息 */
   fingeringInfo: {} as IFingering,
@@ -422,6 +427,13 @@ const state = reactive({
   isEvaluatReport: false,
   /** midi播放器是否初始化中 */  
   midiPlayIniting: false,
+  /** 曲目信息 */
+  songs: {} as ISonges,  
+  isAppPlay: false, // 是否是app播放
+  /** 音频播放器实例 */
+  audiosInstance: null as any,
+  /** midi音频的时长 */
+  durationNum: 0,
 });
 const browserInfo = browser();
 let offset_duration = 0;
@@ -581,7 +593,14 @@ export const skipNotePlay = (itemIndex: number, isStart = false) => {
  * @param playState 可选: 默认 undefined, 需要切换的状态 play:播放, paused: 暂停
  */
 export const togglePlay = async (playState?: "play" | "paused") => {
-  state.playState = playState ? playState : state.playState === "paused" ? "play" : "paused";
+  // midi播放
+  if (state.isAppPlay) {
+    const cloudGetMediaStatus = await api_cloudGetMediaStatus();
+    const status = cloudGetMediaStatus?.content.status
+    state.playState = status
+  } else {
+    state.playState = playState ? playState : state.playState === "paused" ? "play" : "paused";
+  }
   if (state.playState === "play" && state.sectionStatus && state.section.length == 2 && state.playProgress === 0) {
     resetPlaybackToStart();
   }
@@ -983,6 +1002,8 @@ const setState = (data: any, index: number) => {
   // state.isOpenMetronome = data.isUseSystemBeat ? false : true;
   state.isOpenMetronome = data.isPlayBeat && !data.isUseSystemBeat ? true : false
   state.isShowFingering = data.isShowFingering ? true : false;
+  // 设置曲谱的播放模式, APP播放(midi音频是app播放) | h5播放
+  state.isAppPlay = data.playMode === 'MIDI';
   state.music = data.music;
   state.accompany = data.accompany;
   state.midiUrl = data.midiFileUrl;

+ 24 - 3
src/view/audio-list/index.tsx

@@ -9,10 +9,11 @@ import {
 	setMidiCurrentTime,
 } from "./midiPlayer";
 import state, { IPlayState, onEnded, onPlay } from "/src/state";
-import { api_playProgress } from "/src/helpers/communication";
+import { api_playProgress, api_cloudTimeUpdae } from "/src/helpers/communication";
 import { evaluatingData } from "/src/view/evaluating";
+import { cloudToggleState } from "/src/helpers/midiPlay"
 
-const audioData = reactive({
+export const audioData = reactive({
 	songEle: null as unknown as HTMLAudioElement,
 	backgroundEle: null as unknown as HTMLAudioElement,
 	midiRender: false,
@@ -28,7 +29,8 @@ export const audioListStart = (type: "play" | "paused") => {
 	}
 	// 如果是midi播放
 	if (audioData.midiRender) {
-		handleTogglePlayMidi(type);
+		// handleTogglePlayMidi(type);
+		cloudToggleState();
 		return;
 	}
 	if (type === "play") {
@@ -166,6 +168,23 @@ export default defineComponent({
 			}
 		};
 
+		// midi播放进度回调
+		const midiProgress = (res: any) => {
+			const currentTime = res?.currentTime || res?.content?.currentTime;
+			const total = res?.totalDuration || res?.content?.totalDuration;
+			const time = currentTime / 1000;
+			audioData.progress = time;
+			audioData.songEle && (audioData.songEle.currentTime = time);
+			audioData.backgroundEle && (audioData.backgroundEle.currentTime = time);
+			audioData.duration = total / 1000;
+			if (
+				res?.content?.totalDuration > 1000 &&
+				currentTime >= total
+			) {
+				onEnded();
+			}
+		}
+
 		onMounted(() => {
 			if (state.playMode !== "MIDI") {
 				Promise.all([createAudio(state.music), createAudio(state.accompany)]).then(
@@ -190,6 +209,8 @@ export default defineComponent({
 
 				api_playProgress(progress);
 			}
+			// 监听midi播放进度
+			api_cloudTimeUpdae(midiProgress);
 		});
 
 		// console.log(state.playMode, state.midiUrl);

+ 4 - 0
src/view/audio-list/midiPlayer.tsx

@@ -1,3 +1,7 @@
+/**
+ * h5播放midi
+ */
+
 import { defineComponent, reactive } from "vue";
 import state, { gotoNext, onEnded, onPlay } from "/src/state";