Wizard Notes

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

JavaScript:React+Audioオブジェクトで音声ファイルをアップロード&再生

f:id:Kurene:20220219230725p:plain

Webアプリで音声の再生を実現する方法としては、

  • HTMLの<audio> 要素の利用
  • JSのWebAudioAPIでAudioBufferを読み込み

がよく知られています。

遅延が許されない効果音や、信号処理をして再生するような用途ではAudioBufferを読み込みますが、Javascriptでの実装が少しだけ多くなります

一方、用途によっては<audio> 要素のインターフェースであるHTMLAudioElement オブジェクト (Audio オブジェクト) を操作する方が簡単書くことができます

そこで、この記事では ReactとAudio オブジェクトを使ってローカルの音声ファイルを再生するWebアプリ の実装方法を紹介します。

実装

HTML (index.html)

Reactを利用するため、index.html自体はスクリプトの呼び出しなど最低限の記述のみとします。

この中で呼び出している upload_audiofile.jsx にオーディオファイルのアップロード管理と再生機能を実装します。

Reactについてはこちらの記事などを参考にしてください。

www.wizard-notes.com

 <!DOCTYPE html>
<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <script src="https://unpkg.com/react@16/umd/react.development.js" crossorigin></script>
    <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js" crossorigin></script>
    <script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
  </head>

  <body>
    <div id="root"></div>
    <script type="text/babel" src="upload_audiofile.jsx" defer></script>
  </body>
</html>

Javascript upload_audiofile.jsx

<input type="file">で音源がアップロードされonChangeが発火したらAudioオブジェクトを準備します。

2回目のアップロード以降は、資源節約のためにAudioオブジェクトのsrcを更新することでAudioオブジェクトを再利用しています。

// オーディオファイルのアップロード管理と再生機能管理クラス
class AudioFilePlayer extends React.Component {
  // コンストラクタ
  constructor(props) {
    super(props);
    this.audio = null;
    // イベント発火時の処理を行うメソッドについては、
    // this をバインドして束縛する
    this.play  = this.play.bind(this);
    this.pause = this.pause.bind(this);
    this.stop  = this.stop.bind(this);
    this.handleChangeFile = this.handleChangeFile.bind(this);
  }

  // 再生
  play () { 
    if (this.audio == null) { return ; }
    this.audio.play();
  }
  // 一時停止
  pause () { 
    if (this.audio == null) { return ; }
    this.audio.pause(); 
  }
  // 終了
  stop () { 
    if (this.audio == null) { return ; }
    this.audio.pause(); 
    this.audio.currentTime = 0; 
  }
  
  // ファイルがアップロードされたときの処理
  handleChangeFile (e) {
    // オーディオファイルを読み込み
    const file = e.target.files[0]
    // file を参照するための一時的なURLを作成
    const fileUrl = URL.createObjectURL(file); 
    
    if (this.audio != null) {
        // 既にオーディオオブジェクトがある場合、まず再生を停止する
        this.pause();
        // オーディオオブジェクトのURLを変更
        this.audio.src = fileUrl
    }
    else{
        // オーディオオブジェクト作成
        this.audio = new Audio(fileUrl);
    }
    this.audio.load(); // 明示的に読み込みを支持
  };
  
  render () {
    return (
     <div>
        <input type="file" accept="audio/*" onChange={(e) => this.handleChangeFile(e)} />
        <audio id="audiofile-player" />
        <button onClick={() => this.play()} >Play</button>
        <button onClick={() => this.pause()} >Pause</button>
        <button onClick={() => this.stop()} >Stop</button>
     </div>
    );
  }
}

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

デモ (CodePen)

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

参考