index.tsx 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. import { computed, defineComponent, onMounted, reactive, ref, watch } from "vue";
  2. import styles from "./index.module.less";
  3. import { getMidiCurrentTime, getMidiDuration, handleTogglePlayMidi, hanldeInitMidiData, hanldeSetMidiPlaybackRate, setMidiCurrentTime } from "./midiPlayer";
  4. import state, { IPlayState, onEnded, onPlay } from "/src/state";
  5. const audioData = reactive({
  6. songEle: null as unknown as HTMLAudioElement,
  7. backgroundEle: null as unknown as HTMLAudioElement,
  8. midiRender: false,
  9. });
  10. const midiRef = ref();
  11. /** 播放或暂停 */
  12. export const audioListStart = (type: "play" | "paused") => {
  13. // 如果是midi播放
  14. if (audioData.midiRender) {
  15. handleTogglePlayMidi(type);
  16. return;
  17. }
  18. if (type === "play") {
  19. audioData.songEle?.play();
  20. audioData.backgroundEle?.play();
  21. } else if (type === "paused") {
  22. audioData.songEle?.pause();
  23. audioData.backgroundEle?.pause();
  24. }
  25. };
  26. /** 设置倍数播放 */
  27. export const setAudioPlaybackRate = (rate: number) => {
  28. // 如果是midi播放
  29. if (audioData.midiRender) {
  30. hanldeSetMidiPlaybackRate(rate);
  31. return;
  32. }
  33. audioData.songEle && (audioData.songEle.playbackRate = rate);
  34. audioData.backgroundEle && (audioData.backgroundEle.playbackRate = rate);
  35. };
  36. /** 获取当前播放的时间 */
  37. export const getAudioCurrentTime = () => {
  38. // 如果是midi播放
  39. if (audioData.midiRender) {
  40. const c = getMidiCurrentTime();
  41. return c;
  42. }
  43. if (state.playSource === "music") return audioData.songEle?.currentTime;
  44. if (state.playSource === "background") return audioData.backgroundEle?.currentTime;
  45. return audioData.songEle?.currentTime;
  46. };
  47. /** 获取曲谱的总时间 */
  48. export const getAudioDuration = () => {
  49. // 如果是midi播放
  50. if (audioData.midiRender) {
  51. const d = getMidiDuration();
  52. return d;
  53. }
  54. return audioData.songEle?.duration || audioData.backgroundEle?.duration || 0;
  55. };
  56. /** 设置播放的开始时间 */
  57. export const setAudioCurrentTime = (time: number, index = 0) => {
  58. // 如果是midi播放
  59. if (audioData.midiRender) {
  60. setMidiCurrentTime(index);
  61. return;
  62. }
  63. audioData.songEle && (audioData.songEle.currentTime = time);
  64. audioData.backgroundEle && (audioData.backgroundEle.currentTime = time);
  65. };
  66. /** 设置当前没有播放的音频静音 */
  67. export const toggleMutePlayAudio = (source: IPlayState, muted: boolean) => {
  68. if (source === "music") {
  69. if (audioData.songEle) {
  70. audioData.songEle.muted = muted;
  71. }
  72. } else if (source === "background") {
  73. if (audioData.backgroundEle) {
  74. audioData.backgroundEle.muted = muted;
  75. }
  76. }
  77. };
  78. /** 检测音源数量 */
  79. export const detectTheNumberOfSoundSources = () => {
  80. let total = 0;
  81. if (audioData.songEle) total += 1;
  82. if (audioData.backgroundEle) total += 1;
  83. return total;
  84. };
  85. export default defineComponent({
  86. name: "audio-list",
  87. setup() {
  88. /** iframe 加载完成后, 加载midiURL */
  89. const handleLoad = () => {
  90. midiRef.value.contentWindow.handleRendered = () => {
  91. audioData.midiRender = true;
  92. };
  93. hanldeInitMidiData(midiRef.value);
  94. };
  95. watch(
  96. () => state.playSource,
  97. () => {
  98. if (state.modeType === "evaluating" && !state.setting.enableAccompaniment) {
  99. console.log("评测模式设置了关闭伴奏,不切换原音伴奏");
  100. return;
  101. }
  102. if (state.playSource === "music") {
  103. audioData.songEle && (audioData.songEle.muted = false);
  104. audioData.backgroundEle && (audioData.backgroundEle.muted = true);
  105. } else {
  106. audioData.songEle && (audioData.songEle.muted = true);
  107. audioData.backgroundEle && (audioData.backgroundEle.muted = false);
  108. }
  109. }
  110. );
  111. const createAudio = (src: string): Promise<HTMLAudioElement | null> => {
  112. return new Promise((resolve) => {
  113. const a = new Audio(src);
  114. a.load();
  115. a.onloadedmetadata = () => {
  116. resolve(a);
  117. };
  118. a.onerror = () => {
  119. resolve(null);
  120. };
  121. });
  122. };
  123. onMounted(() => {
  124. if (state.playMode !== "MIDI") {
  125. Promise.all([createAudio(state.music), createAudio(state.accompany)]).then(([music, accompany]) => {
  126. // console.log(music, accompany);
  127. if (music) {
  128. audioData.songEle = music;
  129. }
  130. if (accompany) {
  131. audioData.backgroundEle = accompany;
  132. }
  133. if (audioData.songEle) {
  134. audioData.songEle.addEventListener("play", onPlay);
  135. audioData.songEle.addEventListener("ended", onEnded);
  136. accompany && (accompany.muted = true)
  137. } else if (audioData.backgroundEle) {
  138. audioData.backgroundEle.addEventListener("play", onPlay);
  139. audioData.backgroundEle.addEventListener("ended", onEnded);
  140. }
  141. });
  142. }
  143. });
  144. // console.log(state.playMode, state.midiUrl);
  145. return () => (
  146. <div class={styles.audioList}>
  147. {state.playMode === "MIDI" && state.speed != 0 && <iframe style={{ display: "none" }} ref={midiRef} src={`/midi/index.html`} onLoad={handleLoad} />}
  148. </div>
  149. );
  150. },
  151. });