ブラウザで動く波形編集アプリをReactで作った
リンク
以下のURLから登録不要で起動できます。
目指したもの
誰でも直感的に操作がわかる波形編集アプリ。
機能
- 複数ファイルのインポート、結合
- フェード
- クリップごとの音量調整
- クリップの分割・長さの調整
- コンプレッサー
- EQ
- リバーブ
- VUメーター
- wavファイルでのエクスポート
技術スタック
- Typescript
- React
- styled-components
- zustand
- Tone.js
- Netlify
Reactとかstyled-componentsについて言うことは特に無いので、zustandとTone.jsのみ所感を書きます。
zustand - 状態管理ライブラリ
zustand はreduxのような状態管理ライブラリです。ただreduxと比べて以下のような特徴があります。
- fluxアーキテクチャのような縛りがなく、ボイラープレートコードが少ない。
- ストアはただのグローバルオブジェクトみたいなイメージで、なんでも放り込める(それが良いかは別として)。
- selectorはredux同様で柔軟に書ける。
- Providerで囲む必要がない。
シンプルに、サクッとグローバルステートを管理するぶんにはかなり便利に感じます。それでいてselectorや購読を使いこなせばパフォーマンスチューニングもしっかりできる。
ただ、そうとうに柔軟なことができてしまうので、大人数で大規模な開発をする場合は向かないかもしれません。
Tone.js
Tone.js には全面的にお世話になっています。
Webアプリでオーディオを扱う以上、WebAudioAPIを使うことになるわけですが、Tone.jsはさらに高レベルのAPIを提供してくれます。
たとえば、生のWebAudioAPIでは AudioContext
の持つクロックを使用して音源の再生タイミングをスケジューリングするんですが、これはコンテクスト作成時からひたすら加算されていく時間に過ぎません。音楽的な「拍」の概念はありません。
Tone.jsの Transport
はその無機的なクロックをいい感じにラッピングして、音楽的なタイミングでの再生をサポートしてくれます。リピートや、音源を途中から再生したときの処理もよしなにしてくれます。
ただ一点引っかかったのは、3バンドイコライザの実装である EQ3
の音質がかなりアレだということです。githubのissueとしても挙がっていましたが、全バンドを0にしていてもカットオフ周波数あたりが相当に削れているようです。メンテナによると仕様らしいので、僕の使い方がどこか間違っていたのか・・・? FonoではBiquad Filterを使って自前の実装をしています。
TODO
波形のレンダリング
オーディオ波形はcanvasに描画しています。wavesurferの実装を参考にしたんですが、パフォーマンス不足によりズームやクリップ長の変更時にガクガクします。別にjavascriptの限界というわけではなく、他の波形編集アプリを触ってみるとスムースに動いているので、ここは改善したいです。
エフェクト
エフェクトの種類もそうですが、範囲指定で適用できるようにしたいですね。
タイムラインの表示
拡大・縮小してもつねに1秒単位で刻まれているのをなんとかしたい。
Discussion
wavのエクスポートはTone.jsの機能ですか?
Web Auido APIでミックスしたオーディオファイルをエクスポートする方法をググると、録音する方法ばっかり出てくるので、「一々音を最初から最後まで再生して録音することなく、エクスポートできてる!」と思って感動しました。
AudioBuffer
からwavファイルを生成するのは以下のようなスクリプトで行っています(このブログを参考にしました)。ただマスターに接続されているエフェクトや音源をすべて書き出したい場合は、
OfflineContext
にバックグラウンドでレンダリングして、そのバッファーをソースにする必要があります。しかもプレイバック用のノードをそのまま使えるわけではないので、常に同期しておくか最後にクローンしなければいけないので結構面倒です。(という理解ですが、間違っていたらすみません・・・)OfflineContext
自体はWebAudioAPIに存在していますが、これもTone.jsを使うといろいろな便利機能が使えます。