AIイラストをBGMに合わせてほんのりと踊らせてみる
前回の記事「Web Audio APIでAIイラストをリップシンクさせてみた」では、AI絵になんちゃってリップシンクを実装しました。
その後、面白がって声ではなくBGMを入れて遊んでいたのですが、ふと、あれ?これBGMに合わせて踊らせられるのでは?と思いついたので、雑に実装してみました。
BGMに合わせてAIイラストを動かしてみるテスト
BGM入替:
なんだろう…
微妙にリズム感のない娘が踊ってる感がおもしろいwww
音の強度?音圧?、そのへんよくわかりませんが、ともかく、その値によってスピードを調整しています。がしかし、腰ふる距離も変えないとイマイチだったかなぁ。画像全体をX座標で微妙に揺らして誤魔化すのもアリだったかも知れない。
でもそもそもスペクトラム解析がワンテンポ遅れてるのではないかな。…そりゃそうか。最初に一括で解析した後、ダンスモーション作るか、わざとワンテンポ送らせてから音再生するようなことができればもうちょいクオリティ上がるかも。
BGM素材
創作堂さくら紅葉様のBGMを使用させて頂きました。
フリー素材の提供に感謝いたします。
ベース絵
Prompt
highres,detailed eyes
,1girl,flat chest,(naked),white panties
,short twintail hair,small smile
,dancing
,(simple white background)
Negative prompt: (worst quality, low quality:1.2),monochrome,lowres,bad anatomy,watermark, text, sketch,missing finger,extra finger
Steps: 30, Sampler: DPM++ 2M Karras, CFG scale: 7, Seed: 3137890330, Size: 512x768, Model hash: 6df59b69e0, Model: kaywaii_v65, Denoising strength: 0.75, Clip skip: 2, ADetailer model: face_yolov8n.pt, ADetailer confidence: 0.3, ADetailer dilate/erode: 4, ADetailer mask blur: 4, ADetailer denoising strength: 0.4, ADetailer inpaint only masked: True, ADetailer inpaint padding: 32, ADetailer version: 23.10.1, Version: v1.6.0-2-g4afaaf8a
モデルはKayWaii v6.5で、いつもどおりnaked+white pantiesでベースとなるヌードを出した後、Inpaintで服を着せてパーツ切り抜きしています。
最初はやってらんねーと思っていたパーツ切り抜き作業も慣れたもんで5分かからず出来ちゃいますね。AIイラストのガチャのほうが時間かかります。
差分
こちらもいつもどおりGIMPのワープ変形&アニメーション作成機能で16フレーム分(往復で30フレームになる計算)出して、ImageMagickで1枚に結合して、いわゆるスプライトシートというものにしています。
作業時間は5分くらいかな。スカートのウエストが合わなくてやりなおしたから10分くらいかも。
技術解説
前回の記事でも書いたとおり、こちらのいろは様がアップした記事がすべてです。神です。
Web Audio APIでリップシンク(もどき)を作ってみた話
https://qiita.com/iroha71/items/2867f61f459a333ffeb3
当方で変更したことといえば、読み取りタイミングと盛り上がり(?)の検出くらいです。
読み取りタイミングについて
元記事では50ミリ秒ごとにスペクトル解析する仕組みでしたが、こちらは60fps(60分の1秒)でAI絵を描画しているので、それに合わせて約16ミリ秒くらいで解析するようにしました。…ちょっと早すぎるかな?
また、元記事では開口(大)/開口(小)/閉口の3種類でわけていましたが、こちらは画像用意する必要もなくスピード調整だけなので、4種類に増やしています。
let spectrums = new Uint8Array(analyser.fftSize);
analyser.getByteFrequencyData(spectrums);
const totalSpectrum = spectrums.reduce(function(a, x) { return a + x });
if (totalSpectrum > prevSpec) {
this.speedTarget = 120;
} else if (prevSpec - totalSpectrum < 500) {
this.speedTarget = 30;
} else if (prevSpec - totalSpectrum < 1000) {
this.speedTarget = 60;
} else {
this.speedTarget = 20;
}
いきなりスピードが変わると急ブレーキかかったみたいで気持ち悪いかな?と慣性を利かせているのですが、このせいでより一層リズム感がなくなっている気がします。…が、おもしろいので修正しないw
盛り上がりの検出について
音関係はホント専門外なのでよくわからんのですが、スペクトルの合計値で開口判定をしているようなので、じゃあこの値使えば良いのかな?ということで、120フレーム分、約2秒間のスペクトルの平均値を算出し、そこから〇〇%大きくなったか、小さくなったか、で音楽の盛り上がりの判定をしています。
specArray.push(totalSpectrum);
if (specArray.length > 120) {
specArray.shift();
specAvg = specArray.reduce((a, b) => a + b) / specArray.length;
}
if (this.count % 15 == 0 && specAvg !== null) {
if (specAvg * 1.8 < totalSpectrum) { //平均より80%大きくなった場合
this.yAdd = 4;
this.yMin = -30;
this.yMax = 30;
} else if (specAvg * 1.4 < totalSpectrum) { //平均より40%大きくなった場合
this.yAdd = 2;
this.yMin = -20;
this.yMax = 20;
} else if (specAvg * 0.7 > totalSpectrum) { //平均より30%小さくなった場合
this.yAdd = 1;
this.yMin = -10;
this.yMax = 10;
}
}
盛り上がってきたら、キャラクターの上下(UPDOWN)の速度や範囲が増えるというだけ。
昼飯食べてる間に思いついて、夕飯食べる前に実装したような突貫工事なのでいろいろ雑だけど、何かの参考になれば幸いです。
まとめ
技術の無駄使いたーのしー!!












