こちらはマストドンインスタンス「best-friends.chat」にてろびにゃんが企画したアドベントカレンダー2020の記事です。(今年はラマーズPで管理しているマストドンインスタンス「friends.cafe」ではアドベントカレンダーを行わなかったので,「best-friends.chat」のほうにお邪魔させていただきました。)

マジカルミライ2020プログラミングコンテストとは?

初音ミクさんのライブイベントであるマジカルミライ2020にて開催された一般公募のプログラミングコンテストで,産業技術総合研究所で研究開発されたTextAliveというサービスを用いてテーマ曲に合わせて動く歌詞アニメーションを作るコンテストでした。

使用言語はjavascript

ブラウザベースで動作するサービスですので,使用する技術はjavascriptが基本になります。(あと基本的なHTML+CSS)

私の場合,javascriptは言語としてはよくわかっているものの,知識が古くて2000年~2009年あたりまでの知識しかありませんでした。(Ajaxと呼ばれるXMLHttpRequestを使った非同期通信やprototype.js使うくらいまでしかちゃんと使ったことがありませんでした。)

2010年以降,jQueryが幅を利かせてきて,知らないうちにNode.jsができていたものの,当時はもうあまりウェブ開発をしなくなっていたことから,そのあたりの技術にはついていけていなかったわけですが…。【しかし,私が管理するマストドンインスタンスはタイムラインのストリーミングにNode.jsを使っている…。】

そして,今回はjavascriptで映像表現をしなければならないということで困ったなと…。どんなライブラリを使うのが良いのか…さっぱりわからない。というわけでまずは映像表現を何かしらのライブラリを使ってやってるサンプルをベースに…ということで次のサンプルを参考に開発に着手することにしました。

これは p5.js という2Dの図形描画が行えるライブラリを使った作例です。
さくっとソースを眺めてみた感じでは,p5.setupにてキャンバスサイズやフレームレートを設定してキャンバスを作成すれば,あとは p5.draw が定期的に呼び出されるので,ここで様々な描画を行えば良さそうな感じです。

まずはサンプルを動かす開発環境作り

まずは開発環境を作りました。

基本的には静的コンテンツなので,WEBサーバーさえあれば動くんですが,一応効率的に開発するためにも README に従ってNode.jsでPARCELな環境環境を整えようかなということになりました。(PARCELも使うの初めてなんだよね…)

はじめは自分のWindows PC内でやっていたんですが,なんだかわからんけどいろいろなところで躓いてしまったので挫折しました。

これはWindowsだから悪いんだと思い,ConoHa のVPSでUbuntuのサーバーを立ててやったところうまくいったので,そのやり方を載せておきます。

1.ConoHaでUbuntuのサーバーをつくる。

これはConoHaのサポートページのリンク張っておきます。
上から順番にやっていけば作れます。

  • VPSを追加する
    ここでメモリ1GBのサーバーを選べばとりあえずだいたいOKです。
    イメージタイプはOSからUbuntuの20.04LTSを選びましょう。
    また,オプション欄からSSH Keyを作っておくとSSHで接続するとき使えます。
  • SSH接続でVPSにログインする
    適当なクライアントソフトで接続しましょう。
    VPS作成時にSSH Keyを作っておけば公開鍵認証でしかログインできないようになっていると思いますので,(テスト用のサーバーということで…)rootでそのまま公開鍵認証でログインすればいいでしょう…。(説明がめんどくさくなった。ちゃんとログイン用ユーザーとか作るといいと思います。)
    公開鍵認証を設定するのページにおけるプライベートキーのダウンロードまではVPS作成時のSSH Keyの作成で完了しているでしょうから,「公開鍵認証を設定したVPSへのSSHログイン」以下の部分をすることで接続できると思います。

なお,うちではPuTTYというクライアントでPageant+に鍵を持たせてログインしています。PuTTYの使い方はググってください。

2.サーバーの設定

まずは次のような感じで Node.js をインストールします。

# apt update
# apt upgrade
# apt install nodejs
# apt install npm
# shutdown -r now

一応説明しておくと,aptコマンドのupdate&upgradeでOSにインストールされているパッケージを最新版にアプデします。

それから nodejs と npm(パッケージマネージャー)をインストールして VPSを一旦再起動しています。

3.githubへのリポジトリの作成

今回はTextAlive App API p5.js exampleをベースに開発するので,このページをforkして自分のリポジトリを作成します。

右上にForkボタンがあります。

サンプルのページ右上に Fork ボタンがあります。
これを押すだけで自分のリポジトリに複製されます。⇒ こうなる

4.VPSサーバーとgithubをSSH接続し,ソースコードをもってくる。

以下のページを参考にして鍵を生成してgithubには公開鍵を,VPSサーバーには秘密鍵を持っておきましょう。

接続テスト

$ ssh -T git@github.com
Enter passphrase for key '/home/ahox_zy4cc/.ssh/id_rsa':
Hi ahox! You've successfully authenticated, but GitHub does not provide shell access.

準備できたらSSHで接続してソースをCloneしてきます。

まずは開発用のディレクトリを作成。

$ mkdir mm20-procon
$ cd mm20-procon/

git cloneでソースをダウンロードします。

$ git clone git@github.com:ahox/textalive-app-p5js.git
Cloning into 'textalive-app-p5js'...
Warning: Permanently added the RSA host key for IP address '**.***.**.**' to the list of known hosts.
Enter passphrase for key '/home/ahox_zy4cc/.ssh/id_rsa':
remote: Enumerating objects: 3, done.
remote: Counting objects: 100% (3/3), done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
Receiving objects: 100% (3/3), done.

みたいな感じ(※)で,ファイルがダウンロードされます。

※実際に開発始めたときは p5.js のサンプルからforkせずに作ったので,上の例はオブジェクト数などが違います…。でも説明用にはforkしてしまったほうが速かったので…。

5.サンプルを動かす。

ダウンロードしたソースコードはリポジトリ名のディレクトリに入っているのでcdで移動しておきます。

$ cd textalive-app-p5js/

そのディレクトリで npm install を行うことで必要なファイル一式が入ります。すごいですね。これは,リポジトリ内のpackage.jsonに必要なものが全部書かれているので全部入ってくれるようになっています。npm知らなかったから,この辺しらべて理解するのも手間でしたね…。

$ npm install

> deasync@0.1.20 install /home/ahox_zy4cc/mm20-procon/textalive-app-p5js/node_modules/deasync
> node ./build.js

`linux-x64-node-10` exists; testing
Binary is fine; exiting

> core-js@2.6.11 postinstall /home/ahox_zy4cc/mm20-procon/textalive-app-p5js/node_modules/core-js
> node -e "try{require('./postinstall')}catch(e){}"

Thank you for using core-js ( https://github.com/zloirock/core-js ) for polyfilling JavaScript standard library!

The project needs your help! Please consider supporting of core-js on Open Collective or Patreon:
> https://opencollective.com/core-js
> https://www.patreon.com/zloirock

Also, the author of core-js ( https://github.com/zloirock ) is looking for a good job -)


> parcel-bundler@1.12.4 postinstall /home/ahox_zy4cc/mm20-procon/textalive-app-p5js/node_modules/parcel-bundler
> node -e "console.log('\u001b[35m\u001b[1mLove Parcel? You can now donate to our open collective:\u001b[22m\u001b[39m\n > \u001b[34mhttps://opencollective.com/parcel/donate\u001b[0m')"

Love Parcel? You can now donate to our open collective:
 > https://opencollective.com/parcel/donate
npm WARN optional SKIPPING OPTIONAL DEPENDENCY: fsevents@1.2.13 (node_modules/fsevents):
npm WARN notsup SKIPPING OPTIONAL DEPENDENCY: Unsupported platform for fsevents@1.2.13: wanted {"os":"darwin","arch":"any"} (current: {"os":"linux","arch":"x64"})

added 854 packages from 540 contributors and audited 856 packages in 20.851s

36 packages are looking for funding
  run `npm fund` for details

found 1 high severity vulnerability
  run `npm audit fix` to fix them, or `npm audit` for details

最後になんか1件警告が出てますけど(found 1 high severity vulnerability)これは脆弱性に対する警告らしく,

$ npm audit fix

で修正されます。その後ろのnpm fundは資金提供を呼び掛けるものなのでスルーしてOKです。

さて,これで p5.jsのサンプルを動かすための準備が整いました。

次のコマンドを実行すれば,ブラウザから「サーバーのIPアドレス:1234ポート」へアクセスすることで動作確認できます。

$ npm run dev

> textalive-app-p5js@1.0.0 dev /home/ahox_zy4cc/mm20-procon/textalive-app-p5js
> parcel src/index.html --out-dir dev

Server running at http://localhost:1234
⚠️  Could not load existing sourcemap of "../node_modules/songle-api/lib/api.js".
✨  Built in 27.33s.

さて p5.js で開発だ・・・。

と,思うじゃないですか。

実はこの時点で 2020/11/02 でした。

うちのマストドンでは状況報告していました。

応募締切が2020/11/03なのでもはや前日ですね。

全然間に合わない\(^o^)/

敗因

敗因は主に「コロナの影響で楽しみにしていたマジカルミライへ行くことができなくなり精神的に落ち込んでいたから」です。(理由は,職場がコロナ感染拡大している東京および大阪への渡航禁止を命じていたことと,妻が妊娠している状況だったので親戚からコロナ感染拡大している地域への渡航を反対されたためです。田舎なので親戚が世間体も気にしており,感染防止対策の徹底などの理屈で説得するのは不可能な状況でした。コロナ絶対許さん…。)

ツアーも予約してチケットも確保していたし,MEIKOさんの等身大立像プロジェクトにも名前入る金額出資していたのに,行けなくなるなんて辛すぎて死んでましたよね…。

でもまぁ10月も終わるころ,初音ミクシンフォニーにも行けなくてさらに落ち込んでいたわけですが,それでもちょっとでも着手したいと思って,やってみました。結果的に間に合わなかったわけですが,npmとPARCELとp5.jsの使い方について勉強になったので今後役立てていきたいなと思います。(マストドンアカウントと連携して遊べるブラウザゲームでも作るかも。)

もうすこし続きます。

ここからが今回の成果物です。

しかし,せっかくここまでしたのだから p5.js ちょっと使ってみようよってことで,以下のリポジトリにあるようなものをその後作りました。

ここでは次のようなp5.jsの機能を試しています。

点の描画位置を時間的に変化させてワープしているような表現

ここでは, p5.point(x,y) で点を描画していますが,描画位置x, yおよび点の大きさwを時間 tt により変化させることで星間をワープしてるっぽくしてみました。

p5.curvePoint 関数は,補助点x1-始点x2-終点x3-補助点x4で示される曲線のうち,ttt=0~1の範囲に相当する点の位置を返す関数です。

# 381行目
p5.drawBackgroundWarp=()=>{
...
# 435行目
if ((t0 <= tt) && (tt < t1)){
    const ttt = (tt-t0) / (t1-t0);
    const x=p5.curvePoint(x1,x2,x3,x4,ttt);
    const y=p5.curvePoint(y1,y2,y3,y4,ttt);
    const w=p5.curvePoint(w1,w2,w3,w4,ttt);
    switch (params.bgWarpObjType){
        case "point":
            p5.strokeWeight(w);
            p5.point(x, y);
            break;
    }
}
}

音声波形のような表現

ここでは,TextAlive APIで取得できる音量(Volume)を取得し,音量に応じた振幅の波線を描画して,音声波形のようにしています。

# 451行目
p5.drawBackgroundWave=()=>{
...
# 527行目
let i = 0;
let wave = dataStore.background.wave;
p5.beginShape();
for (i=0; i<count; i++){
    p5.curveVertex(
        i * width / count,
        sign * (2*(i%2)-1) * wave.historyVolume[i] / wave.maxVolume * height / 2 + height / 2
    );
}
p5.endShape();
}

wave.historyVolumeにAPIから取得した現在の再生位置付近の音量を格納しておき,それに基づいてp5.curveVertexで曲線を描いています。

TextAlive API で取得できるデータはいろいろあります。

今回私が作成したリポジトリのデータでは以下の部分を true に設定することで,APIで取得した数値をリアルタイムに画面上に表示できますので,それを見ると開発が捗ると思います。

# 231行目
// DEBUG MODE
devMode: false

その他

シーンチェンジ機構もどきを作ってた

README にも書いていますが,今回はソースコード冒頭の

const myenv = {
...
	// 演出設定
	templateMap:
...
}

にて,用いる演出の種類を時間(startIndex~endIndex)で区切って設定すれば,選択した関数と設定したパラメータで動画が変化するようにしています。(将来的には様々な演出を用意しておいて,曲のシーンに合わせて演出をチョイスできるように。)

基本的に歌詞を用いた演出を要素ごとに分解すると「背景」「歌詞の描画方法(位置決めと大きさやフォント)」「歌詞の文字に合わせて出てくる演出(文字の周りに円を描くなど,文字の描画位置を中心として決まる演出)」になると思います。なので,それらの演出を大量に用意しておいて,あとは環境変数で設定してやると動画が作れるみたいな感じです。

p5.js は座標をベースとして描画には強いし,使い勝手も悪くないと思いましたので,なんでも努力次第で表現できるのではないかなと思います。

npmでいろんなパッケージも使いたかった

また,npmで他にも使えるライブラリを導入してもいいかもしれません。(ソースコードには,うっすら fontawesomeでいろいろな絵文字を出そうとした痕跡が残っています…。)

ライブラリを追加するときは,npm installで一緒にインストールされるように,–save-devとか–saveを使いましょう。こうすることで,package.jsonに追加されるので,別の環境で npm install したときに一緒にインストールされるようになります。

$ npm install --save-dev パッケージ名

みんなもコードを書いてたくさんgithubにpushしよう

コードを書いたら以下のようにしてリモートリポジトリに反映しましょう。

コミットする際の初期設定

$ git config --global user.email "ahox@friends.cafe"
$ git config --global user.name "ahox"

すべてのファイルをステージングする(git管理下に追加する)

$ git add .

コミットする(変更内容を記録する)

$ git commit -m "Setup TextAlive p5.js example."
[master 99d119c] Setup TextAlive p5.js example.
 6 files changed, 8253 insertions(+)
 create mode 100644 .gitignore
 create mode 100644 package-lock.json
 create mode 100644 package.json
 create mode 100644 src/index.css
 create mode 100644 src/index.html
 create mode 100644 src/index.js

リモートリポジトリに反映する

$ git push
Enter passphrase for key '/home/ahox_zy4cc/.ssh/id_rsa':
Enumerating objects: 10, done.
Counting objects: 100% (10/10), done.
Delta compression using up to 2 threads
Compressing objects: 100% (8/8), done.
Writing objects: 100% (9/9), 79.63 KiB | 5.69 MiB/s, done.
Total 9 (delta 0), reused 0 (delta 0)
To github.com:ahox/magicalmirai-procon.git
   86fef10..99d119c  master -> master

おわり。

みなさんも何かを機会にプログラミングやってみましょう。おもしろいですよ。

そして github にどんどん公開していきましょう。今時 git くらい使えないといけませんからね(←いつも使い方がよくわからなくなる人)

そして私は1秒でも早くコロナが収束して,またミクさんのイベントに行ける日が来ることを祈っています。(さっぽろ雪まつり,どうなるんだろうか…。)

しかし,ミクさんがコロナに感染する恐れがないことだけが救いですね…。

今年は年の初めにMIKUEXPO in ヨーロッパで,ドイツ・オランダ・スペイン遠征したのが頂上で,その後はチケットを取っていたUSAでのコーチェラが中止,浄瑠璃も中止になり,秋以降は浄瑠璃に行けない…。シンフォニーに行けない…。マジカルミライに行けない…。ということで,ずっと気分が低迷しておりましたが,来年は良い年になることを祈っています。

それではまた,次のミライで会いましょう。

良いお年を。

カテゴリー: PROG

0件のコメント

コメントする

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください