カテゴリー: プログラム

HTLM5、JavascriptでAudioオブジェクトのcurrentTime = 0では頭出しができなくなる現象について

非常にご無沙汰をしております。tongでございます。
ここまで間があいてしまいますと「あんた誰?」みたいな方ばかりかと思いますが、自己紹介は無しの方向でお願いします。
私事で色々ございましてなりを潜めておりましたが生活の為にお仕事はする訳で、そこで「ちょいとハマった」事があって調べても中々わからなかったので、ここに書いておけば誰かの助けになるかなと言う事で書いておこうと思います。

背景説明としてはWebアプリの開発から7年くらい離れていたのですが、色々あって昔 自分がFlashで作った真面目な仕事のWebアプリ化を断ったら他所に頼んだけど失敗したので再度舞い戻って来た。って感じの話。

記事内容はタイトルの通りで、ネットワークの遅延を防ぐために100個位の短い音声ファイル(えっちぃ声じゃ無いよ)を先読みしてユーザー操作に応じて再生するって感じの挙動。

引っかかったのは2点で、一つは動的にAudio「タグ」を大量に生成してHTMLのエレメントに追加するとFirefoxでは読み込みに引っ掛かりが出る場合があること。
今回はAudioタグのコントロールを表示したりしないので、Javascriptのオブジェクトとして扱ってやれば回避可能でした。

もう一つは、Mac OS XのApple Safariのみ先読みした音声ファイルの2度目の再生が出来ない、あるいは途中から再生されると言う現象。
最初は「またアップルかっ!」とキレそうになるも、そこはホレ大人ですから落ち着いてよく考えてみる。
すると、まず途中から再生されるのは1回目の再生時に最後まで再生されない場合に再生位置が残っているのでは無いかと言う推察に至ります。

途中から再生されちゃダメなら再生前に頭出しすりゃ良いじゃん。って事で「currentTime = 0」を入れる訳ですが、これが出来ない。

なにこれ?

ReadOnlyでもないプロパティーに値がセットできないのは変です。異常です。
この辺をWebで検索するとSafariとChromeの自動再生回避ばかりが引っかかるんだけど、そうじゃないんだよね・・・
って事でさらに調べて行くと「new Audio(‘URL’)でAudioオブジェクトを再度作るとcurrentTime = 0じゃ無くても頭出しできるよっ」みたいな記述がSafari開発者のコミュニティーで見つかったので早速実装。

ふむ、確かにSafariでは動く。しかし他のブラウザでテストを行うとFireFoxで動かないでは無いか。
件のページにも今のSafariは「さすがはSafari、大量にオブジェクトを作っても何とも無いぜ」だけど昔は大量にオブジェクトをnewすると動作が不安定になったってあって「やっぱりアップル関係者はSafariしか考えてないなっ!」となって居た訳です。

その後もcurrentTime = 0関連で、メモリー上に「先頭が0以外の値のAudioストリームデーターはcurrentTimeを0に出来ない」とか、色々出てきて「先頭が0以外の値のAudioストリームデーター」ってどんなよ?ってなるのですが、「あぁユーザーがコントローラーで再生位置をジャンプしたりするとそうなるか、メモリー上に無いなら出来ないわな」。
そして「new Audio(‘URL’)」で解消できるって事はダメな時はメモリー上にデーターが無かったって事であり、currentTime = 0に気を取られていたけど、これはもっと別の現象なのではと言う考えに至り・・・

そう、そうなんです。
これは「何らかの原因でメモリー上に音声データーが無い」事が原因なんですね。

ここで種明かしをすると、この現象はガーベイジコレクトが原因なんですね。
と言うか昔、同じECMAスクリプトであるActionScriptでも同じ現象に出くわした事が有った気がしてきました。

ガーベイジコレクトとは使用メモリーの節約機能で、ロードやアクセスしてから時間が経ったオブジェクトはエントリのためのオブジェクトのガワだけ残して実体はメモリーから削除されちゃうんです。
このため最初の頃はちゃんと再生できていた音声が時間が経つと正しく再生できなかったり、頭出しが出来ない等の現象が起きてしまう訳です。

では具体的にはどう対策したらよいのかと言いますと、new Audio(‘URL’)でAudioオブジェクトを大量に作ると言う方法ではAudioオブジェクトの作り過ぎでスマートじゃない。何よりFireFoxで動かないなどの弊害があります。
これを回避するには、新しくオブジェクトを作るのではなくAudioオブジェクト.load(‘URL’)とします。

//先読みでデーターをロードする
let soundObj_0 = new Audio(‘sound/sound_0.mp3’); //プリロード


//どのタイミングで音声データーが使われるか分からないので
//使うときはとにかくloadしてしまう
soundObj_0.load(‘sound/sound_0.mp3’); //再生前に無条件にロード
soundObj_0.currentTime = 0;  //念のために再生位置を0リセット
soundObj_0.play();  //音声再生

こんな感じですかね。

なお、2回目のload(‘URL’)はブラウザ キャッシュからロードが行われるので読み込みにネットワークの遅延は出ないようです。

めでたしめでたし。


WordPress で自動ギャラリーページ

らくがき置き場

以前のブログにあった「ギャラリー」ページですが、WordPress 更新でプラグインが動かなくなってしまったので久方止めていました。でも「あれ? この画像、前にも上げなかったっけ」と思うことがあり、最近の WordPress はメディアライブラリも一気に一覧表示されなくなったので、確認にちょっと不便。

元々使っていたプラグインは特定のカテゴリーに投稿した画像を一気に抜いて表示するものだったんですが、他のを探してもそれっぽいのがない。WordPress のギャラリー機能を使おうにも、過去画像に遡ってタグ付けしないとならないようで、ちょー面倒。

結局、固定ページのテンプレートを自作しちゃいました(笑) 2日ぐらいかかったので、素直にメディアライブラリでタグ付けした方が良かったかも…

→らくがき置き場

でも記事をカテゴリー分けするだけで、勝手に固定ページに投稿画像が追加されるので便利ですよ。たぶん。

需要はないかもですが、主要な部分のソースコード(page-gallery.php)置いておきますね。一応、出力タグは <figure> とか使って Gutenberg に遵守。なお前後のコードは使用中のテーマファイルの page.php に合わせないと、デザインが崩れると思うのであしからず。


Adobe Animate CC(旧Flash Professional CC)の不具合メモ

現在作成中のゲームはFlash Professional CCを使ってAdobe Air で開発していますが、先日Flash ProfessionalがAdobe Animate CCに名称変更されました。
で、インストールして試してみましたが致命的なバグがあったのでメモしておきます。

  • 作成しているAriアプリケーションの内容
    XMLに記述されているファイル一覧を元に外部ファイルを読み込みユーザーの操作に応じて適宜再生表示する。
  • 不具合発生の経緯
    Adobe Animate CCからAri インストーラーを書き出してインストール実行しAir アプリケーションを起動しても、自動で読み込まれるはずのファイルが読み込まれず停止する。
  • 不具合の考察
    試しにインストール先のフォルダに読み込むファイルを全部コピーすると正常に起動するのでファイル名が異常かファイル一覧の文字化けのどちらかが疑われる。
  • と言う事で外部ファイルが入っているフォルダをエクスプローラーで開くと一部、全く同名のファイルが2つ存在する!と言うなかなかシュールな絵面になっている事を発見。

    Adobe AnimateCCの不具合

    Adobe AnimateCCの不具合

と言う事でコマンドプロンプトで「Dir」を掛けてみるとファイル名が2バイト文字かつ「濁点、半濁点」を含んでいた場合に元の文字+「゛」または「゜」と言う感じにファイル名が変わっている事が判明(ただし、エクスプローラーでは正しいファイル名の様に見える)

Flash Professionalではこのような現象は発生していないので当面はFlash Professionalに戻して開発を続けてます。

まぁファイル名に2バイト文字を使うなって話かもしれませんが、やらなくても良いアップデートでファイル操作と言う基本的な個所にバグを混入してくるのはマジ勘弁って感じです。


AEアニメについての知見

開発中のゲームは「いじりゲー」にカテゴライズされます。
そして「いじりゲー」に不可欠なのがエロいアニメーションです。
ご存じのとおりアニメには2Dと3Dがあり、当方的には今から使い慣れたツールであるPhotoshopのデーターからアニメーションを起こせるAfterEffectsを使って2Dアニメを作るのが一番リーズナブルかなと考え、ここ数年試行錯誤を繰り返してきました。
ところがWebでAEアニメ関連のノウハウを探してもあまり見つからないんですよね。
なので、覚書も兼ねて当方の気付いたことを書いておこうかなと思います。

  1. 絵を作りこむPSDとAEに読み込むPSDは別物にする。
    これは読み込んだ時点には存在していたレイヤーがなくなった場合など、PSDのレイヤー構造が途中で変わるとAE側でエラーが出る事を防ぐ事が目的です。
    例えば、img_101_org.psdをコピーしてレイヤーやレイヤーグループを整理したimg_101_integrated.psdを作成してAEにはこれを読み込ませます。
    AEの読み込んだ後にPSDを変更する必要が生じたときはimg_101_org.psdを修正して修正したレイヤーをimg_101_integrated.psdに複製して再統合、レイヤー名を合わせて保存すると、AE側で開いたときエラーもなく変更が反映された状態になります。
  2. AEに読み込むPSDはレイヤーグループをなるべく使わずシンプルにする。
  3. 絵を作りこむPSDの塗はグループマスクを使う
    AEに読み込ませる絵は一枚絵の場合とは異なり動く部分の影になる所まで書き込む必要があります。そのため、例えば手や足の絵と胴体のレイヤーを分けて描かなくてはなりません。
    またレイヤー分けした手足と胴体は主線が無い場合がほとんどなので「アルファ―チャネルで滑らかに繋げる」ことが必須です。
    通常肌の塗等は複数レイヤーを使う方が多いと思うのですが、各レイヤー毎にやわらかい消しゴムで消してしまうと作業が増えるだけでなく、レイヤー毎でボケ足が統一できない等の不具合が起きます。
    その場合は複数ある塗りのレイヤーをレイヤーグループにまとめレイヤーグループにボケ足の着いたマスクを掛ける事で回避できます。

あと、AEではなくてFlashのActionScript3のTipですがマウスイベントは複数のイベントリスナーを設定した場合、イベントが伝わるのに「時差」がある事を最近発見しました。
しかも、その時差は実行するパソコンの処理能力に左右されるのでタイミングが関係するような処理はイベントリスナーを複数使うと意図した動作に「ならない場合」があります。
(ただし、これはマウスイベントに限定した現象らしく他のイベントでは発生しないみたいです)

最近は「Live2D」や「Spine」などPSDからアニメーションを起こすツールも増えてきましたがこの覚書の内容はAE以外でも通用するのではないかと思います。(と言うか最近Adobeの品質劣化が激しいのでCLIP STUDIOSpineUNITY に移行してやろうか等と考えている当方だったりします)


Adobe JavaScript

前回投稿のエロゲ用動画作成は進んではいるのですが、AEとPhotoshopの連携で自分がやろうとしている事が世間様的あるいは業界的には異端なせいなのか今一つ使い勝手がよろしくないんですよね。
当座困っている事が2つあって、一つはAEはコンポジションのデュレーション(動画の尺)や背景色を一括して変更する仕組みが見つからなかったので一つずつチマチマ直していたんですけど1プロジェクト内のコンポジション数が150超えたり、そんなプロジェクトが恐らく50くらいあるのでとても手作業では追いつかない。

と言う事でAdobe JavaScriptと言うものを使って自動処理させることにしました。
内容はシンプルなものでプロジェクト内のアイテムをForループで一つ一つ調べてコンポジションなら背景色とデュレーションを決められた値に書き換えると言うもの。
面倒なのでインターフェイスとかも作らず背景色の指定とかもハードコーディングと言う超手抜きですが、今まで30分掛かって居た事が5秒で終わる、すばらしい(笑

もう一つはAEにPSDファイルを読みこませるとグループなどのレイヤー構造をコンポジションとしてプロジェクトに登録してくれるのですがコンポジション名=グループ名なところ。
例えば以下のようなレイヤー構造のPSDがあったとします。

頭横向き(グループ)
├目(グループ)
│ ├目 怒り(レイヤー)
│ ├目 普通(レイヤー)
│ ├目 泣き(レイヤー)
│ └目 笑い(レイヤー)
├口(グループ)
│ ├口 怒り(レイヤー)
│ ├口 普通(レイヤー)
│ ├口 泣き(レイヤー)
│ └口 笑い(レイヤー)
└頭ベース(グループ)
├頭線画
└頭塗
頭正面(グループ)
├目(グループ)
│ ├目 怒り(レイヤー)
│ ├目 普通(レイヤー)
│ ├目 泣き(レイヤー)
│ └目 笑い(レイヤー)
├口(グループ)
│ ├口 怒り(レイヤー)
│ ├口 普通(レイヤー)
│ ├口 泣き(レイヤー)
│ └口 笑い(レイヤー)
└頭ベース(グループ)
├頭線画(レイヤー)
└頭塗(レイヤー)
体(グループ)
├腕(レイヤー)

表情や顔の向きなどの差分があるので同じレイヤー名やグループ名のものがたくさんあります。
で、これをAEに取り込むのですが、右側の「理想」のようになってくれれば良いのですがプロジェクトのコンポジションは左側の「現実」のようになります。(チッ)

現実 理想





頭ベース
頭ベース
頭横向き
頭正面

頭横向き
頭横向き 目
頭横向き 口
頭横向き 頭ベース
頭正面
頭正面 目
頭正面 口
頭正面 頭ベース


要するにAEのプロジェクト内のコンポジション名にはPhotoshopの「上位のレイヤー名が飛ぶ」のでコンポジション名だけを見たのでは親レイヤーが何だったのかが分からないのです。
これを防ぐにはPhotoshop側のレイヤー名やグループ名を「上位レイヤー名も含めた形にしておく」事しかないのですが、これがレイヤーが大量にあってまた大変なんですね。(1ファイル毎でレイヤーを統合してもレイヤー、グループ合わせて500位にはなってしまいます)
でも、このままだと一々上位のコンポジションが何なのかを調べながら動画を作らなければならないのですが、まぁ非常に効率が悪いですわな。

と言う事で、これまた調べてゆくとPhotoshopでもAdobe JavaScriptが使えてレイヤー名を変更出来るみたいなんですね。さすがPro用のツールって所でしょうか。
Photoshop用のスクリプトはこれから作るのですが、一段落したらこう言ったツールもここで公開出来たらよいかなとか思ったりしてます。
まぁ、現在進行中のエロゲの方が先なのですが・・・

5月25日追記:実際に作ってみたらレイヤーの選択が遅い遅い。
レイヤー、グループ合わせて500程度のPSDで20分以上かかると言う体たらく・・・
割高になったサブスクリプションを正当化するためにどうでも良いタブレット用のデッサンツールとかより、こう言う所やファーストリリースのバグを減らしてマトモにするとかもっと力を入れるところあるでしょ。って感じですわ