File size: 2,094 Bytes
64ddb35
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
"use client";
import { useEffect, useRef, useState } from 'react';
import MidiPlayer from 'midi-player-js';
import Soundfont from 'soundfont-player';

// 這是一段 C 大調音階的 MIDI 檔案,使用 Base64 編碼寫死在程式碼中
// 這樣就不需要使用者上傳檔案了
const C_MAJOR_SCALE_BASE64 = 'data:audio/midi;base64,TVRoZAAAAAYAAQABAIxNVHJrAAAAGwD/BAcCBQNkgEN/AP8vAE1UcmsAAAAqAP8DBFNrYWxhAP8EDgIFA2SAQ38AkEIAAACQQwAAAJBFAACQSQAAAP8vAA==';

export default function Home() {
  const [isReady, setIsReady] = useState(false);
  const player = useRef<MidiPlayer.Player | null>(null);

  useEffect(() => {
    // 整個初始化過程都在 useEffect 中,確保只在瀏覽器端執行
    const audioContext = new AudioContext();

    // 1. 載入樂器 (Soundfont)
    Soundfont.instrument(audioContext, 'acoustic_grand_piano').then(instrument => {
      
      // 2. 初始化 MIDI 播放器
      player.current = new MidiPlayer.Player(event => {
        if (event.name === 'Note on' && event.velocity > 0) {
          instrument.play(event.noteName);
        }
      });
      
      // 3. 載入我們寫死的 MIDI 資料
      player.current.loadDataUri(C_MAJOR_SCALE_BASE64);
      
      // 4. 一切準備就緒,更新 UI
      setIsReady(true);
    });

    // 元件卸載時清理 AudioContext
    return () => {
      if (audioContext.state !== 'closed') {
        audioContext.close();
      }
    };
  }, []); // 空依賴陣列確保這個 effect 只執行一次

  const handlePlay = () => {
    player.current?.play();
  };

  return (
    <main style={{ fontFamily: 'sans-serif', textAlign: 'center', paddingTop: '5rem' }}>

      <h1>MIDI Player: Hello World!</h1>

      

      <p>{isReady ? '播放器已就緒!' : '正在載入樂器...'}</p>

      

      <button 

        onClick={handlePlay} 

        disabled={!isReady}

        style={{ fontSize: '1.2rem', padding: '10px 20px', cursor: 'pointer' }}

      >

        🎵 播放 "Hello World" 音階

      </button>

    </main>
  );
}