memorandums

日々の作業ログです。

p5jsでテノリオン的な何かを作ろうとした残骸

絵だけでは行き詰まってきたので音も絡めて何か作れないかと少し作ってみました.p5.soundのおかげで簡単に音を再生できます.機能的にはHTML5のおかげなんでしょうけど...

最初に作ったのがこれ.音ゲーなんかはこれが作れればすぐに作れますね.初心者には少し難しいのですが...

www.openprocessing.org

すぐに思いついたのは四角を丸にすること.機能的には何も変えていません.

www.openprocessing.org

次に,最近,1年生のゼミ(ジェネラティブアート)でセルオートマトンを作ったので,試しに作ってみたのが以下でした.ルールをいろいろと調整してみたのですが...なかなか難しい.

www.openprocessing.org

で,今朝,起きてすぐに作ったのが以下でした.表形式である必要はなく円環状にしたらどうなるかな...とひらめいたのでしたが...音階をイメージしにくく,面積が部位によって異なるので操作性も悪く...微妙でした.

www.openprocessing.org

なかなか難しいですね...新しいものを作るってのは.

はい.

p5.jsでFPSを60以上にあげてみる

厨ニ的な発想ですが...

p5.jsではframeRateで画面のリフレッシュレートを設定できまして,最大が60に設定されています.

ただ,ブラウザのcanvasのリフレッシュレートはもっと上げられるんじゃないか...と想像しまして,p5.jsのソースを読んだりしていました.

p5.jsでは描画関数であるdraw関数を定期的に呼び出すために,window.requestAnimationFrame というものを使用しているらしいことがわかりました.

ぐぐると,Mozillaのサイトに解説がありました.

developer.mozilla.org

1/60秒のタイマーをsetTimeoutで作成するのではなく,あくまでブラウザのタイミングで更新しようという関数のようです.確かにその方が,ブラウザごとの実装に合わせた表示ができそうです.スマートな実装です.

最初,p5.jsのコードに,frameRateに60以上を指定したらif文か何かで制限するコードがあるんじゃないかと思ったのですが...見つからず.このwindow.requestAnimationFrame がそもそも制約を作っていたってわけなんですね.なるほどです.

計測してみたところ,確かに約1/60秒ごとに呼び出されていました(Firefox).

このwindow.requestAnimationFrameとsetTimeoutで動作を比較してみました.

以下,実験コードです.

ブラウザで実行すると2つの□が右に移動していきます.上はwindow.requestAnimationFrameで1/60秒周期で実行したもの.下はsetTimeoutで1/200秒周期で実行したものです.

y座標の変動はそれぞれ指定したFPS(上段は60で下段は200です)の実測値が変動している様子を表しています.細かく波打っていますが,だいたい指定した値で動作するようです.

とりあえず,setTimeoutで指定すればリフレッシュレートを60以上にあげられそうなことがわかりました.

<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="utf-8">
    <title></title>
  </head>
  <body>
    <canvas id="canvas" width="400" height="400"></canvas>
    <script>
      var canvas = document.getElementById("canvas");
      var context = canvas.getContext('2d');
      let x_a=0;
      let x_b=0;

      function a() {
        let et = new Date();
        let dy = (et-st_a-1000/60);
        if (x_a++>400) x_a=0;
        context.strokeRect(x_a, 100+dy, 10, 10);
        window.requestAnimationFrame(a);
        st_a = et;
      }

      function b() {
        let et = new Date();
        let dy = (et-st_b-1000/200);
        if (x_b++>400) x_b=0;
        context.clearRect(0,0,400,400);
        context.strokeRect(x_b, 300+dy, 10, 10);
        setTimeout(b,1000/200);
        st_b = et;
      }

      let st_a = new Date();
      let st_b = st_a;
      a();
      b();
    </script>
  </body>
</html>

さて,お次はp5.jsのコードをちょっと変更してみたいと思います.p5.min.jsだと見にくいので,本家サイトにより圧縮前のソースをダウンロードします.

p5.js ダウンロード

で,p5.jsを取り出して,下図のように55655行から55659行までコメントアウトし,55662行目の1000 / 60の60を変えます.以下は120に変えたところです.最大120FPSで動作するようにできます.

f:id:ke_takahashi:20200802100356p:plain

まぁ,こんなことをやる人はいないでしょうけどね...とりあえず.

せっかくだから比較してみたかったので,p5.jsをインスタンスモードで利用することで,frameRateを60と120で指定して違いをみてみました.

ツイートにも書いているけど,決して滑らかではないんですね...やる前からわかっていたことですが...

ただ,速く回っているだけ...リフレッシュレートの高いディスプレイで表示してみてみたいものです...ヌルヌル動くっていうやつを😁

メモまで,インスタンスモードで比較した○ソコードだけど晒しておきます.

<html>
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <script language="javascript" type="text/javascript" src="p5.js"></script>
  <style> body { padding: 0; margin: 0; } </style>
</head>
<body>
  <table>
    <tr>
      <td>
        <h2>60FPS</h2>
        <div id='fps60'></div>
        実測値(FPS):<div id='fps60_count'></div>
      </td>
      <td>
        <h2>120FPS</h2>
        <div id='fps120'></div>
        実測値(FPS):<div id='fps120_count'></div>
      </td>
    </tr>
  </table>

<script>
 let c60 = [];
 let c120 = [];
 let sketch60 = function(p) {
   p.setup = function() {
     p.createCanvas(300, 300, p.WEBGL);
     p.frameRate(60);
   };
   p.draw = function() {
     p.background(200);
     p.rotateY(p.frameCount * 0.01);
     p.box(150);
     let tag = window.document.getElementById('fps60_count');
     c60.push(p.frameRate()); if (c60.length>10) c60.shift();
     tag.innerHTML = p.int(c60.reduce((accumulator, currentValue) => accumulator + currentValue)/10);
   };
 };
 let st120;
 let sketch120 = function(p) {
   p.setup = function() {
     p.createCanvas(300, 300, p.WEBGL);
     p.frameRate(120);
   };
   p.draw = function() {
     p.background(200);
     p.rotateY(p.frameCount * 0.01);
     p.box(150);
     let tag = window.document.getElementById('fps120_count');
     c120.push(p.frameRate()); if (c120.length>10) c120.shift();
     tag.innerHTML = p.int(c120.reduce((accumulator, currentValue) => accumulator + currentValue)/10);
   };
 };
 new p5(sketch60, window.document.getElementById('fps60'));
 new p5(sketch120, window.document.getElementById('fps120'));
 </script>

</body>
</html>

うーん,何の役に立つんでしょうね...まぁ,いいか.やりたいからやっただけです.

Androidアプリで音がでなくてはまった件

ゼミ生がAndroidアプリ開発を勉強することになり,まずはと思い,初心者向けの以下の本を渡しました(実際のは第3版).

昨年,2年生の少人数ゼミで久しぶりにAndroidアプリ開発でも一緒にやろうと思い,とにかくアプリをたくさん作って楽しめそうな本ということで購入しました.ただ,受講生が20名近くいたため,ゼミ室には入り切らず,Android Studioを自由にいれて動かせる環境がなかったため...ゼミ室に放置した状態でした.

ゼミ生と話したところ,躓いている様子だったので,私も自宅で試してみたわけです.

で,特に問題なく動作することを確認し,ゼミ生にも伝えたあとで,完成したアプリを実機転送して動かしてみたところ音がならない...あれ?

仮想マシンでは音がなります.

で,ログをみると以下のエラーメッセージが出ていました.

W/AudioTrack: AUDIO_OUTPUT_FLAG_FAST denied by server; frameCount 0 -> 262144

ぐぐると書き込みはたくさんあるのですが,具体的な解決方法が見つかりません.あれこれ試してみてもこのメッセージは消えませんでした.

うーん...

結局,原因はこれでした.

f:id:ke_takahashi:20200723221334p:plain

アラーム音の音量がゼロだったんですね...あげたら鳴りました.上記のメッセージは出たままです.関係なかったんですね...あーあ.

音を読み込むところでALARMって打った記憶が蘇ってきて気づきました.途中で.

f:id:ke_takahashi:20200723221457p:plain

しょうもない誤りでしたが...ハードウェアあるあるですね...

初心者なら運悪くアラームの音量をゼロにしていたら...気づくのは難しいでしょうねぇ〜.

最近,プログラミングといえばJavasciptだったので,セミコロンなしの言語に慣れるのに苦労しました...kotlin...すっきり書けているようですが,やっぱりJavaっぽいですねぇ.当然といえば当然ですけど.

はい.連休1日目終了.

あ,そうそう.今日の出来事として.

九州プロレス観てきました.声出したかったけど...難しいですねぇ...でも楽しかったぁ.また行きたいなぁ.

f:id:ke_takahashi:20200723221806j:plain

今度,12周年の無観客試合をオンライン配信するそうです.こちらも楽しみです.ググるとクラファンしてたんですね...知らなかった.

www.youtube.com

Smart Laser CO2の冷却水を交換しやすいようにしてみた

数日前にこんなエントリーを書きまして.

memorandums.hatenablog.com

まだ,交換用のチューブが届いていません.

ただ,冷却キットがノイズ源になるようなので,ちょっとホースを長めにして本体とつなげていたんですね.これだと,発注中のチューブがこないと交換できないのですが,考えてみれば,チューブを短くした方が冷却水は少なくて済むんじゃないかな...と思いまして.

余ったチューブでつなげたら全交換できちゃいました...ってことでした.

2mのチューブを2本も買ったけど...いらなかったというオチになりますが,また交換するときがくるでしょうから保管しておきます.

で,ついでに,冷却水を交換しやすいように,ポンプに戻るチューブを半分でぶった切って,そこに,CO2に付属していた接続パーツ?をつなげてみました.

こんな感じです.ここを外してポンプを回せば冷却水を簡単に交換できます.うーん,我ながらナイスアイデア

f:id:ke_takahashi:20200722104935j:plain

昨日,グッデイで買ってきた漏斗がちょうどポンプの穴にピッタリで!なんてステキなんでしょう😁

ペットボトルから水道水をじゃんじゃんいれてもこぼす心配もありません.

f:id:ke_takahashi:20200722104746j:plain

何回か循環させることで,汚れを落とすことができました.

これで冷却水問題からはオサラバできそうです😁

Smart Laser CO2の冷却チューブの汚れが酷い...

リモートワークが続いています.

それでも講義が混んでいる日や非常勤がある日は出勤しています.だいたい週に2日くらいです.

情報分野なので,講義やゼミなどはリモートでも全く問題ないのですが,研究室にある様々な資材が使えない状況でして...

その1つがレーザーカッターです.

このSmart Laser CO2を購入したのは4年前になります.正確には覚えていませんでしたが,ブログに書いておくと思い出せます.

memorandums.hatenablog.com

購入時にはペットボトルの水をいれて利用していました.1年くらい問題なく使っていたように思います.その後,Facebookのコミュニティで「冷却水に不凍液を使うといいよ」とあったので,早速やってみたようです.

memorandums.hatenablog.com

しばらくそのまま使っていたのですが,昨年,使おうとしたときに水流センサー?が回らなくなり(たぶん不凍液がゲル化した?),水道水に戻しました.それも記録がありました.

memorandums.hatenablog.com

で,昨日です.

チューブをみたところ,黒ずみがあり,よーくみると...水が腐敗した感じになっていました...(汚い画像ですいません...)

f:id:ke_takahashi:20200716153248j:plain
f:id:ke_takahashi:20200716155055j:plain

掃除しようとしたのですが,簡単にはとれそうもありませんでした.

交換チューブをこれから取り寄せて,暇をみつけて全交換しようと思っています.

ただ,やはり水道水がまずかったのか?不凍液を使っていたときから雑菌がはいっていたのか?そもそも,レーザーカッターを使っている方は交換しているのか?など疑問がふつふつとわきまして.

とりあえず,フォーラムの方に投稿させていただいたところでした.

forum.smartdiys.com

循環ポンプが開放なので空気にふれるチャンスはいくらでもありますしね...雑菌が入る機会も繁殖する機会もたっぷりあるような気がします.防腐剤のようなものをいれたらいいのかなぁ...

とりあえずメモでした.

■2020/7/20 追記

smartdiysさんに,冷却チューブのサイズをお尋ねしていたのですが,その返信として,smartdiysさんでも交換用ホースを販売しているとのことでした.2m で 990円とのことで,適合性に不安なく購入できると思い,すぐに購入しました.

smartdiysさんのホームページでは見つからなかったのでモノタロウとかで購入しようと思っていました.もし,チューブの交換を検討されている方がいらっしゃれば,smartdiysさんに問い合わせてみるとよいかもしれません.

ひさしぶりにp5js作品をつくった

昨日,北九州での非常勤を終えて研究室に戻り,1週間分たまった事務仕事を終えて一息ついたときに,一昨日,ウォーキング中に撮影した写真が目に入りました.

こんな写真です.大雨も続きましたし,真夏に入る前の特有?の不安定な空模様です.でも,美しいですよね...天然のパーリンノイズって感じがします.

f:id:ke_takahashi:20200714191113j:plain

で,この色合いをサンプリングして,何か作品が作れないかな...と2,3時間くらい格闘しました.

最初は,適当にサンプリングして,ランダムに配置したのですが,ただの中間色になり...当然といえば当然でした.

もう少し,アルゴリズミックに描画しようと,ランダムウォークするロボットがサンプリングした色を塗り始まるようなものを作ってみたのですが,これも今ひとつでした.

その後,作っては壊してを5,6回くらい繰り返したと思います.

とりあえずそれなりに見栄えのする?作品になったのが以下でした.

www.openprocessing.org

ジェネラティブアート本を1年生のゼミでやっていて,渦巻で遊んだのを思い出して,ロボットの軌跡をランダムウォークから渦巻に変更しました.

あとは等間隔に配置して,角速度や点の大きさなどをマウスをクリックするたびにランダムで決定するようにしました.

色は画像からサンプリングして決定します.配色は参照する画像の開始位置をランダムで決定することでクリックするたびに異なる絵になるようにしました.

ジェネラティブなアルゴリズミックなアートかと勝手に解釈しています.

人様に見せられる(見せているのですが...)ようにするには,もう1・2工夫必要な気がします.

時間があれば,もう少し遊んでみたいと思います😁

AWS Cloud9のインスタンスの自動停止機能?を確認した件

背景

AWS Cloud9でプログラミングの授業を進めています.

調査のため,とあるシェルスクリプトを学生さんに実行してもらおうかと思いつきまして.

ただ,リソースを使用すると学生さんのクレジットが減ってしまうので...スクリプトが動きっぱなしになったら...と思い調べてみました.

AWS Cloud9のFAQページには以下のように書かれています.

よくある質問 - AWS Cloud9 | AWS

AWS Cloud9 EC2 環境 – Cloud9 が接続する新しい Amazon EC2 インスタンスを起動できます。既定では、これらのインスタンスIDE を終了して 30 分後に停止し、IDE を開いたときに自動的に起動します。

このIDEが具体的に何を指しているかが微妙です...タブを閉じれば終了したことになるのか?ブラウザを閉じないといけないのか?ブラウザを閉じたただけで終了とみなされるのか?いろいろ不安が残ります.

とはいえ,Cloud9を使い始めるときには,停止したインスタンスを再起動する画面になりますので,大きな心配はしていなかったのですが...ただ,たまに学生さんから「私のクレジットが残り少ないという警告がでました」という相談があったり...不思議です.

知りたかったこと

Cloud9のターミナル上でスクリプトを実行したあと,IDEを終了したら,スクリプトはどうなるのか?

方法

ターミナルを開いて,以下のスクリプトを実行しました.フォアグラウンドとバックグラウンドで実行しました.

while true; do date; sleep 60; done > file

結果

今朝,出掛けにしかけてきて,今,ファイルを確認したところ,フォアグラウンドとバックグラウンドの両方とも,起動後30分後にプロセスが停止していました.上記のスクリプトが1分ごとに時刻を表示するので,その時刻情報から読み取った結果です.

さらに,2つともプロセスが無くなっていました.なるほど...という感じです.ターミナルから起動したプロセスは休止状態になったときに保存対象とならないようです.これはこれで安全だな...と思いました.

学生さんに渡したスクリプトを1回実行してもらいプログラミング演習してもらい,演習が終わったらIDEを閉じるはずなので,閉じた30分後にインスタンスが停止し,学生さんが実行したスクリプトが停止する...わけです.とりあえず1セッション?分はデータがとれそうです.