JavaScriptのWebAudioAPIで楽曲の口パクをしてみる
以前、ソフトウェアの解説動画を作った際、おっさんの声だけ流れてるのもアレだし、最近流行りのアバターにしゃべらせるやつやってみよう、と思ったことがあります。
vtuberとかおじさんよくわからないので、まずは解説用のテキストを入力→VOICEVOXで合成音声を作成→Puppet3で音を読み取りながら、キャラクターなんとか機で生成したイラストを口パクさせる、ということをしました。
はじめての試みということもあり、作業はとても楽しかったです。
しかし、この口パク、全開か閉口しかない。その2枚のイラストしか作っていないのだから当たり前。
もうちょっと何とか出来ないものかなぁ、と調べていたら…
Web Audio APIでリップシンクもどきを作っている人を発見
Web Audio APIでリップシンク(もどき)を作ってみた話
https://qiita.com/iroha71/items/2867f61f459a333ffeb3
おぉ…おぉ…。これ!これだよ!これがやりたかった。
JavaScriptで動かすことになるので、解説動画作る用途としてはちょっとどうかなと思わなくもないですが、そこはグリーンバックにして合成するなり、動画もJavaScriptで再生しつつ重ね合わせるなり、やりようはいくらでもあるでしょう。
いや、正直に言おう。もう解説動画とかどうでもよくてJavaScriptが書きたい。
Web Audio APIというのは初めて知りましたが、使い方はさほど難しくなさそうだし。
AudioContextを作り、AudioBufferSourceNodeのバッファーに音声ファイルを入れ、AnalyserNodeと接続してから再生させれば、後は好きなタイミングでgetByteFrequencyData関数で各周波数帯域の音量が取れるので合算して音が鳴っているかどうかを判断する、という仕組みです。
サンプルコードでは口の種類を3種類用意していましたが、音量の最大値と最小値を決めて、その割合で口の画像ファイルの高さと幅をリアルタイムで画像加工すれば良いのでは?と感じたので、そのように仕様変更して無事完成しました。
さて、このスクリプトに音声ファイルではなく楽曲をほおりなげたらどうなるのだろう?と早速試してみたら、ドラムの音にあわせて口がパクパク。ぼくはゲラゲラ。
とても楽しい時間を過ごしていたのですが、うーん、真面目に楽曲とボーカル部分の聞き分けって出来ないのだろうか?と疑問に思いました。
その後………………前置き長いわ!!!! 紆余曲折ありましたが、とりあえず試作品が出来たのでUPしておきます。
ボーカル分割口パクテスト
しゃど師匠が作った「人形ふたたび」という楽曲をお借りしました。今から確認するので、たぶん大丈夫だと思うけど、怒られたら変更しますw
技術解説
Web Audio APIを使い、リアルタイムに各周波数帯の音量を取得しているのは前置きで書いたとおり。
最初はこの周波数情報だけを使ってビート(リズム)の検出と、歌声の検出をしようと頑張っていました。
なんとなく、それっぽい感じには出来たものの、ボーカルの声質によって判定箇所を変えないとおかしくなるし、絶妙に楽器と混じって取れないところも多い。
そこで「師匠ぉぉ~~~リズムと音声の判別って出来ないッスか~?!」と泣きついたのだけれど、師匠いわく、同じ周波数帯に音声も楽器もぐちゃぐちゃにまじってしまっているのだから無理、とのこと。世界の研究者たちがちょーがんばって何やら小難しい計算式である程度抽出はできるようになってきたけどそれでも完全ではない、と。
そうかぁ、えらい学者さんたちでも無理なら、ぼくに出来るわけがない。
…と、そこまで話を聞いてふとデジャヴを覚えました。
最近同じような話聞いたな? あれだ、Stable Diffusionだ。
学習段階で元絵をぐっちゃぐちゃにまぜてしまってノイズだらけにしてるのに、その中から求められる絵を構成していくディープラーニングの仕組み。
もしかして、AIの分野で実現してたりしない?
調べたら、ありました。ありましたよ。Demucs-Gui
https://github.com/CarlGao4/Demucs-Gui/releases
ベータ版が2022年に出来たばかりの比較的新しいプロジェクトです。
しかもStable Diffusionなどと違って最初からGUI用意されているので導入も簡単。さっそくWindowsにインストールして音声分離してみたところ、2分の楽曲がわずか10秒程度(RTX4070使用)で音声分離できちゃいました。
そうして分離した音声ファイルを裏でMUTE状態で流しながら口パクしているのが先述のミクさんです。
あ、見ればわかると思いますが、桃色のビジュアライザー(グラフ)が曲全体、赤色がボーカル、緑部分が解析している範囲です。
ボーカル部分は全帯域を見ても良いのですが、一部コーラスが入っているのと、より口の開閉を細かくするためにある程度絞り込んでいます。
スプライトアニメーション
本題からそれますが、ミクさんが微妙に動いているのはcanvas上でのスプライトアニメーション処理です。
Stable Diffusionでフィギュアっぽいミクさんの絵を出力した後、画像加工してこんな感じの9枚のパラパラ漫画を作っているだけ。
9枚の別ファイルにしても良いのだけれど、1ファイルにしといたほうが通信量が減るかな?という、それだけの理由です。
動きについては普段は角度をほんのり動かしつつ、音圧が高まってきたらX/Y座標の動きを激しく、音声の量が増えたらズームイン、減ったらズームアウトという処理をしているだけです。
口差分は以下の画像1枚のみで、JavaScript上で検出した音量に従い大きさを変えています。そんなことより、ミクさんの動きに追従する計算式が面倒だった。
容量の無駄遣いなんだけど、X/Y座標の指定が面倒だったので、全体サイズと同じ透過画像を作って丸ごと貼り付けて目パチにしています。2秒に1回、2分の1の確率で目を6フレームの間だけ閉じます。
まとめ
特に使い道があるわけじゃないんだけど、このプログラミングはちょー楽しかった!!