Processing で音に反応して動くアニメーションを作る(前編)
openFrameworks 等と比較して描画の遅い Processing を使って、音に反応して動くアニメーションを作る方法を考えてみました。
リアルタイムで再生している音源に反応させる方法ではなく、音源ファイルを読み込んでバッチ処理でアニメーションを作成する方法です。
我流で思いついたある一つの方法であって、「これが最適解だ!」というわけではありません。
この記事は全文無料でお読みいただけます。もしお気に召しましたら投げ銭お願いしますね。😉✨
音に反応して動くアニメーション
まず、Processing で音に反応して動くアニメーションを作るための基本形を下記の手順で作成しました。
1. Sound ライブラリを追加
素の Processing には音関係の機能が無いので、別途ライブラリを追加する必要があります。
手順はこちらを参考にさせていただきました。
以前は Minim というライブラリを使うのが定番でしたが、Processing 3 からは Processing Foundation が提供する Sound ライブラリも使えるようになりました。今回はこの Sound ライブラリを使用しました。
2. コードを書く
ズバリ、今回書いたコードは以下です。
/**
* Processing で音反応系の動画を作る(前編)
*
* @author @deconbatch
* @version 0.1
* @license GPL Version 3 http://www.gnu.org/licenses/
* Processing 3.5.3
* 2020.10.10
*/
import processing.sound.*;
int smplRate = 48000;
int frmRate = 24;
Sound snd;
SoundFile sfl;
Amplitude amp;
void setup() {
size(640, 640);
colorMode(HSB, 360.0, 100.0, 100.0, 100.0);
frameRate(frmRate);
snd = new Sound(this);
snd.sampleRate(smplRate);
sfl = new SoundFile(this, "your_sound_file.wav");
sfl.play();
amp = new Amplitude(this);
amp.input(sfl);
}
void draw() {
drawSomething();
if (sfl.isPlaying()) {
saveFrame("frames/####.png");
} else {
exit();
}
}
入力となる音源は ./data/your_sound_file.wav というファイルです。
描画結果は ./frames/ 中に連番のファイル名で png 形式の画像として出力されます。
音源の音量を amp で取り出します。
描画は drawSomething(); で行います。この関数を入れ替えれば様々なアニメーションが作れるというわけです。
描画を下記コードで実行した結果がこちらになります。
float divX = 50.0;
float divY = 20.0;
float eX = 0.0;
float eY = 0.0;
void drawSomething() {
background(0.0, 0.0, 90.0, 100.0);
translate(width * 0.5, height * 0.5);
float eS = 100.0 - amp.analyze() * 50.0;
eX += amp.analyze() * divX;
eY += amp.analyze() * divY;
ellipse(eX, eY, eS, eS);
if (abs(eX) > width * 0.5) {
divX *= -1.0;
}
if (abs(eY) > height * 0.5) {
divY *= -1.0;
}
}
使わせていただいた音源はこちらです。
Pharmacy Party by Steve Combs is licensed under a Attribution 4.0 International (CC BY 4.0)
画像ファイル群から動画を生成する手順はこちらを参照ください。
でも音と絵が合わないよ…
これで出来た!めでたしめでたし!
と、なるかと思いきや、先程のような単純な描画だとよいのですが、ちょっと複雑な描画をしようとすると途端にこうなります。
アニメーションの尺が音源より短くなってる!これは描画に時間がかかってる間に音の再生がどんどん先に進んでしまっているからです。
本当なら 480枚ぐらい描画しなきゃいけないところ半分しか描画できてません。絵の数が少ないのに再生のフレームレートは同じなので時間が短くなってしまってるわけです。
480枚 / 24fps = 20秒
240枚 / 24fps = 10秒 ← 時間が短くなってる
じゃあ、描画に時間がかかる分フレームレートを落とせばいいのでは?
240枚 / 12fps = 20秒 ← fps を落とせば同じ時間
ということで、フレームレートを 10fps まで落として実行してみたのがこちらです。
なるほど尺は合いました。
でも、10fps だとだいぶカクカクしてるし、もっと複雑な描画になったらさらにフレームレートを落とさないといけなくなるんじゃ…?
絵に音を合わせるんだ!
そこで思いついたのが「絵に音を合わせる」です。
描画が遅いなら、元の音源をスローにすればいいじゃない!
元音源のサンプリングレートを落とし、それに比例して再生時間を伸ばした別音源を作り、それを入力として使うのです。
今回の音源のサンプリングレートは 48,000Hz (int smplRate = 48000;) でした。これを 1/8 の 6,000Hz まで落とすことで、元のフレームレート 24fps (int frmRate = 24;) も 1/8 の 3fps 換算とすることが出来ます。
3fps でいいのなら相当複雑が描画が出来そうですよね!
具体的にどうやんの?
音源の変換には ffmpeg を使いました。
一回の変換でテンポは半分(再生時間は2倍)までにしかできないので、下記のように 3回変換して 1/8 (再生時間は 8倍)にしました。
ffmpeg -i input.wav -ar 24000 -af atempo=0.5 -vn temp.24k.wav
ffmpeg -i temp.24k.wav -ar 12000 -af atempo=0.5 -vn temp.12k.wav
ffmpeg -i temp.12k.wav -ar 6000 -af atempo=0.5 -vn output.wav
コードは下記のように変更します。
//int smplRate = 48000;
//int frmRate = 24;
int smplRate = 6000;
int frmRate = 3;
出来上がったファイル群を 24fps(8倍速)で動画に変換すれば元と同じ再生時間のアニメーションになるというわけです。
実行例
先程の 10fpsでカクカクしていた動画はこうなりました。
動きのスピードに音量を反映させた作例だと違いがもっとわかりやすいかもしれません。
blendMode(ADD); でさらに描画に時間がかかる例だとこんな感じに。
このように「絵に音を合わせる」という考え方で、音に反応して動くアニメーションを Processing でも作ることができました。
しかし、これでも描画に分単位で時間のかかる凝った表現は難しいです。
なんとかならないものでしょうか…?🤔
📘 他にも note でいろんな記事書いています。
🐦 Twitter でもいろいろ面白いの上げてるのでぜひフォローしてください。
🎨 こちらのブログはソースコード付きの作品集になってます。
この先には何もありません。この記事がお気に召しましたら投げ銭お願いします。😉✨
ここから先は
¥ 100
この記事が面白かったらサポートしていただけませんか? ぜんざい好きな私に、ぜんざいをお腹いっぱい食べさせてほしい。あなたのことを想いながら食べるから、ぜんざいサポートお願いね 💕