Wizard Notes

Python, JavaScript を使った音楽信号分析の技術録、作曲活動に関する雑記

JavaScript:React+wavesurfer.jsでローカルの音声ファイルの再生・波形表示

JavaScriptで音声を再生・波形表示するのに便利なライブラリとして wavesurfer.js があります。

wavesurfer-js.org

今回はこのwavesurfer.jsを使って、ローカルの音声ファイルを再生・表示するWebアプリを作ります。

JavasScript

wavesurfer.js はオーディオファイルを読み込むたびに波形を描画します。

ここは参考にしたWebサイトより、以下のように実装になっています。

波形等の再描画は wavesurfer.js 側の実装であるため、React側では再描画しないようにする必要があります。 従って、useEffectの第1引数である副作用関数でWaveSurfer.create()を実行し、第2引数に[]を与えることで、初回だけ描画します。

また、初回だけ描画しつつ内部に保持している値(ファイルのURL)のみを更新するため、useRefを利用しています。

ファイルのアップロード等は 以下の Audio オブジェクトを使った音声アップロード&再生の記事の実装をベースにしています。

www.wizard-notes.com

const App = () =>  {
  const waveformRef = React.useRef(null);

  React.useEffect( () => {
    waveformRef.current = WaveSurfer.create({
      container: waveformRef.current,
    });
  }, []);

  const handlePlayPause = () => {
    waveformRef.current.playPause();
  }
  
  const handleChangeFile = (e) => {
    const file = e.target.files[0]
    if (file) {
        const fileUrl = URL.createObjectURL(file)
        waveformRef.current.load(fileUrl); 
    }
  }
      
  return (
    <div>
      <div ref={waveformRef}></div>
      <input type="file" accept="audio/*" onChange={(e) => handleChangeFile(e)} />
      <button onClick={handlePlayPause}>Play/Pause</button>
    </div>
  );
}

ReactDOM.render(<App />, document.getElementById("root"));

Chrome向け

近年のGoogle Chromeでは例えば再生ボタンのクリックなど、ユーザージェスチャー後にAudioContextを作る必要があります

developer.chrome.com

波形表示領域の描画が後でよい場合、例えば以下のようなコードだと動作します。

const WaveSurferUpload = () =>  {
   const waveformRef = React.useRef(null);
   var context = null;
 
   const handlePlayPause = () => {
     waveformRef.current.playPause();
     console.log("handlePlayPause")
   }
   
   const handleChangeFile = (e) => {
     if (context == null) {
         window.AudioContext = window.AudioContext || window.webkitAudioContext;
         context = new AudioContext();

         waveformRef.current = WaveSurfer.create({
            container: waveformRef.current,
            audioContext: context,
         });
     }

     const file = e.target.files[0]
     if (file) {
         const fileUrl = URL.createObjectURL(file)
         waveformRef.current.load(fileUrl); 
     }
   }
       
   return (
     <div>
       <div ref={waveformRef}></div>
       <input type="file" accept="audio/*" onChange={(e) => handleChangeFile(e)} />
       <button onClick={handlePlayPause}>Play/Pause</button>
     </div>
   );
}

デモ

See the Pen react_wavesurfer by Kurene (@_kurene) on CodePen.

参考 Web サイト