JavaScriptで音声を再生・波形表示するのに便利なライブラリとして wavesurfer.js があります。
今回はこのwavesurfer.jsを使って、ローカルの音声ファイルを再生・表示するWebアプリを作ります。
JavasScript
wavesurfer.js はオーディオファイルを読み込むたびに波形を描画します。
ここは参考にしたWebサイトより、以下のように実装になっています。
波形等の再描画は wavesurfer.js 側の実装であるため、React側では再描画しないようにする必要があります。
従って、useEffect
の第1引数である副作用関数でWaveSurfer.create()
を実行し、第2引数に[]
を与えることで、初回だけ描画します。
また、初回だけ描画しつつ内部に保持している値(ファイルのURL)のみを更新するため、useRef
を利用しています。
ファイルのアップロード等は 以下の Audio オブジェクトを使った音声アップロード&再生の記事の実装をベースにしています。
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
を作る必要があります。
波形表示領域の描画が後でよい場合、例えば以下のようなコードだと動作します。
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.