Hatena::ブログ(Diary)

Yanagi Entertainment

2010-04-27

[] Ruby1.9のlambdaをアロー演算子に。Hash#perlish!

Ruby1.9ではlambdaを->で書けるようになりました。

lambda { |x| x+1 }  # これと
-> x { x+1 }        # これは等価

lambdaと->は文法上の扱いが異なります。

p(lambda{})   # => <Proc:0x9696dc@(irb):1 (lambda)>
plambda{}     # NoMethodError
p(->{})       # => <Proc:0x95e29c@(irb):2 (lambda)>
p->{}         # => <Proc:0x95bea0@(irb):3 (lambda)>

要するに->{}はデリミタ不要ということです。楽しいですね。

ところで、p->{}なんて形はPerlリファレンスにしか見えません。なのでPerl風のアクセスができるようにしてみましょう。

$binding = binding

class Hash
  def perlish!(bind = $binding)
    id = self.object_id
    that = self
    bind.eval("local_variables").each{|sym|
      if id == bind.eval("#{sym.to_s}.object_id")
        Object.__send__(:define_method, sym, -> x { that[x.call] })
        break;
      end
    }
  end
end

こんなスクリプトを実行すると、

h = {"key" => :value}
h["key"]     # => :value

h.perlish!

p h->{"key"} # => :value
p h.class    # => Hash

Perlのリファレンスみたいな感じでHashにアクセスできるようになります*1。楽しいですね。

*1:文法の制約からリファレンスを引けるのは一段まで。h->{"abc"}->{"def"}みたいなことはできない。

2010-04-06

[] WebブラウザGoogle Waveで動くシーケンサ、Anzutoneリリース!

f:id:yanagia:20100407000204p:image


http://anzutone.appspot.com/

読み方は「あんずとーん」です。


これはなに?

SafariFirefoxで動くミュージックシーケンサです*1

非常にシンプルな機能しか備えていませんが、「みんなで作曲できます」。


みんなで作曲できる

上記サイトのAnzutoneは通常版ですが、Google Waveで動くバージョンもあります。

テンプレートは以下に。

Anzutone Gadgetのテンプレート

このガジェットはAnzutoneをGoogle Waveでも動くようにしたものです。

通常版との違いは「みんなで作曲できる」ことです。ぜひお試しください。

ただ、非常に横幅の広いガジェットなので取り扱いには注意してください。


ソースとか

オープンソースです。MITライセンス

Githubホスティングしてます。


今後の展望

ノープランです。

いくつか追加したい機能はあるのですが、明日から大学でコミットが少なくなるのでなんとも言えません。

Google Wave API Challengeには応募しようと思っていますが、あれってガジェットもOKなんでしょうか?


技術的なこと

Web WorkersをユーザコードのSandboxとして使うアイディア*2jQuery UI 1.8のハマリどころ、

audioタグの振る舞いがブラウザ・OSによって全く違うこと、などなど言いたいことはたくさんあるので後日別エントリにまとめます。


あと、僕はFlashとかサーブレットとか書けないので全部JavaScriptの実装になってます。


制作の経緯

通常版のAnzutoneは春休みの総まとめで作ったようなもの*3なんですが、Google Wave版は別の動機があります。

今のGoogle Waveの先、そこにはネット上のありとあらゆるドキュメントがリアルタイムでユーザーに編集され正しい姿を目指して常に形を変え続ける、そういう未来があります。どうでしょう、そう考えるとわくわくしてきませんか?

http://d.hatena.ne.jp/technohippy/20091130#1259592204

このエントリを読んだから、僕はGoogle Waveのガジェットを作りました。


僕には3つのPと言われても、あんまりピンと来ないけれど、

色々なものをみんなで一緒に作れるようになったら、すごく楽しいですよね。

*1Google Chromeでは動きません。

*2:我ながらこのアイディアは素晴らしい。

*3:Webブラウザで動画編集→波形処理→波形再生ときて、シーケンサ作れるじゃん。作るか。作った。という流れ。

2010-03-23

[][] JavaScriptで波をつくろう。リアルタイム波形生成&再生

前のエントリでこんなことを書きました。

JavaScriptで波形データを読み書きすることができる。しかし再生するのは難しい。

HTML5のaudioタグとData URIを組み合わせればできないこともないが、コストが大きすぎる。

コストが大きいのは音声ファイルが大きいからです。50MBある波形をいちいち変換してられません。

でも小さい波形ならできるかもしれない! ということでやってみました。


基本的なアイディア

  1. 波形データをつくる(数値の配列
  2. 波形をバイナリ列に変換する
  3. バイナリ列にWAVヘッダを付加する
  4. Base64エンコード
  5. audioタグのsrc属性に指定
  6. audioを再生

つくったもの

http://yanagiatool.appspot.com/jsaudio/mmltest.html

シンプルなMMLプレイヤーです。JavaScript + HTML5。

ベロシティとかループとかはありませんが、かえるのうたは演奏できます。

演奏に使う波形は下のテキストボックスで制御できます。


実際のコードとかはgithubに。


大雑把なしくみ解説

「リアルタイムレンダリング」のほうは音符ひとつにつきWAVファイルをひとつ生成し、タイマーでスケジューリングして鳴らしてます。

WAVファイルは再生前に"作り置き"するのではなく、再生中に動的に生成しています。

オフラインレンダリング」は再生前に全てのWAVファイルを生成、JavaScriptでそれらを合成してひとつの大きなWAVにしてからaudioタグに渡してます。


もう少し細かなしくみ解説

「リアルタイムレンダリング」はレンダリングコールバックを定義して、setIntervalで定期的に呼び出しています。

var Timer;

function play(){ // ボタンが押されるとこの関数が呼ばれる
  ... // 再生開始の準備
  Timer = setInterval(renderBar,  // レンダリングコールバック
			     1000 * ((60.0 / Score.bpm) / (16 / 4))); // 16分音符の長さ
}

コールバックの中で波形とaudioタグを生成して再生バッファに突っ込みます。音符ひとつにつきaudioタグひとつ。

var renderBuffer = [];

function renderBar(){  // レンダリングコールバック
  var note;
  ... // 音符のコレクションから「今発音すべき音符」を探索してくる

  var signal = createSignal(note.duration, note.pitch);  // 波形を動的に生成
  var url = convertToURL(signal); // 波形にWAVEヘッダを付与、Base64エンコード
  var audio = new Audio(url); // audio要素を生成
 
  document.getElementById("anywhere").appendChild(audio); // audio要素をhtmlに追加。この時点でurlからロードがはじまる
  renderBuffer.push(audio); // すぐには再生できないので、一旦バッファに貯めておく

  ... // 他に発音すべき音符がないか確認

  setTimeout(playBuffer, 10);  // 再生バッファを再生
}

function playBuffer(){
  for(var i = 0; i < renderBuffer.length; i++){
    renderBuffer[i].play();
  }
  renderBuffer = [];  // バッファをクリア
}

また、このアプローチだと再生が終わったaudioタグは不要になるので、適当なタイミングで要素を削除するコードも差し込みます。

  audio.pause();
  document.getElementById("anywhere").removeChild(audio); // HTMLからの参照を切る。これでGCされる

波形の生成について

今回使用している波形のフォーマットは以下の通りです。

ページのユーザーコードは上のフォーマットの数値配列を返却することを期待しています。

数値配列は以下のコードでunsigned char(8bit)のバイナリに変換できます。

  var signal = userSignal;
  var binary = "";
  for(var i = 0; i < signal.length; i++){
    binary += String.fromCharCode(signal[i]);
  }
}

波形をData URIに変換する

波形バイナリにWAVヘッダを付加する

以下のコードで、44100Hzの8bitモノラルな波形バイナリにヘッダを付加できます。

  var signals = "波形のバイナリ";
  var header;

  header = "WAVEfmt " + String.fromCharCode(16, 0, 0, 0);
  header += String.fromCharCode(1, 0); // format id
  header += String.fromCharCode(1, 0); // channels
  header += String.fromCharCode(68, 172, 0, 0); // sampling rate
  header += String.fromCharCode(68, 172, 0, 0); // byte/sec
  header += String.fromCharCode(1, 0); // block size
  header += String.fromCharCode(8, 0); // byte/sample
  header += "data";		       // data chunk label

  var siglen = signals.length;
  var sigsize;

  sigsize = String.fromCharCode((siglen >> 0 & 0xFF),
				(siglen >> 8 & 0xFF),
				(siglen >> 16 & 0xFF),
				(siglen >> 24 & 0xFF));

  header += sigsize;

  var wavlen = header.length + signals.length;
  var riff = "RIFF";
  
  riff += String.fromCharCode((wavlen >> 0 & 0xFF),
			      (wavlen >> 8 & 0xFF),
			      (wavlen >> 16 & 0xFF),
			      (wavlen >> 24 & 0xFF));
 
 wavefile = riff + header + signals;

このコードは

WAV ファイルフォーマット

http://www.kk.iij4u.or.jp/~kondo/wave/

を参考にして作成しました。thanks!


バイナリをBase64エンコード

楽をしたいので変換モジュールを探してきます。

今回は弾さんのbase64.jsを使いました。

javascript - Yet Another Base64 transcoder

http://blog.livedoor.jp/dankogai/archives/51067688.html

thanks!


エンコードした文字列に "data:audio/wav;base64" を付加

concatするだけです。


これだけの知識があれば上のサンプルと同じものがつくれます!

やったね!


つくりながら思ったこと

リアルタイムレンダリングは厳しい

audioタグはこういう用途で使われることを想定していないようで、どのブラウザでもいまいち綺麗に鳴りません。

試した中ではFirefoxが一番うまくいっていましたが、アクティビティモニタでスレッド数を確認すると楽しいことに*1

MacSafariプロセス間通信しまくりでダメダメでした。Appleは「Flashなんて必要ない」と言う前にaudioタグを改善するべきです。


オフラインレンダリングは使える

ブラウザのaudioタグがダメダメなら全部JavaScriptでやってしまえばいい、というのがオフラインレンダリング。

個人的な感触では、これ、使えます。いけます。

リアルタイムでやるよりも(波形合成のコストがある分)やや重いですが、オフラインならaudioタグに触る必要がないのでWeb Workersで処理できます。

少なくともユーザーにリアルタイムだと勘違いさせる程度の処理速度は実現できそうな感じです。


HTML5すごい! で終わらせたくない

こういう感じのエントリを書くと、「HTML5すげー、JavaScriptすげー」みたいな反応をよく聞きます。

でもそれだけで終わらせるのはもったいないです。

僕はJavaScript歴4ヶ月のビギナーですが、上のプログラムを6時間で書くことができました。

もしあなたが僕よりも長くJavaScriptを使っているのなら、より良いものをより短い時間で作ることができるかもしれません。

僕の知らないAjaxの世界で、もっと面白いことができるのかもしれません。


まとめ

Canvas、Video、AudioとJavaScriptでマルチメディア処理をする技術は出揃いました。

あとはクリエイターのアイディアと、少しのコーディングで"波"をつくることができます。

楽しくて、面白くて、みんなとつながる、大きな"波"をつくることができます。


準備はすべて整いました。

JavaScriptで、"波"をつくりましょう。


*1:どうやらaudioタグの数だけスレッドを生成しているようです。

2010-03-16

[] JavaScriptwavファイルを読み込んで波形表示するサンプル

動画でリッチなことできるんなら音声でもできるんじゃね? と思ったので書いてみました。

http://yanagiatool.appspot.com/jsaudio/load.html (FireFox3.6系列のみ)

f:id:yanagia:20100316213833p:image

ローカルからwavファイルを画面にドラッグアンドドロップしてみてください。ゆっくり波形が表示されます。

読み込めるwavファイルの形式は16bitステレオのみです。


仕組み

File APIを使ってます。

FileReaderでファイルの中身をStringとして読み込んで、ヘッダをチェックして、データ部を適当にエンディアン変換しながら表示してます。

File APIの使い方やバイナリの扱い方などは

W3C File APIを使ってJavaScriptでファイル加工 - しばそんノート

http://d.hatena.ne.jp/shibason/20100111/1263191021

が参考になりました。thx


作ってて思ったこと

JavaScriptだと、波形と音声が繋がらないなーと。

今回作ったスクリプトは波形のデータを全部配列に持っていて、それを直接編集することができます。

でも加工した波形データを再生するうまい手段がHTML5/JavaScriptにはなくて*1、こういうことをやる旨みって少ないのかなあと思ったりしました。

var speaker = new SoundOutputUnit();
speaker.renderCallback = function(time){
 ...
}

speaker.start();

みたいなことができるようになると、すごく面白くなるとは思うんですが。

*1:audioタグにdataスキームで渡すという方法はあるけど、50MBのwavを毎回出力するわけにはいかないし。

2010-02-26

[] Webブラウザで動画編集!

html5で videoの任意のフレームをcanvasに描画するメモ - 超自己満足プログラミング

http://d.hatena.ne.jp/favril/20100225/1267099197

昨日この記事を見て、これはすごい! すごいすごい! ってなって、これができるんならWebブラウザだけで動画編集できるんじゃね? と思ったりしたので、ざっくり作ってみました。


http://yanagiatool.appspot.com/jsvideo/player.html (MacSafari4で動作確認。QuickTime + ChromeならWindowsでもいけるかも?)

f:id:yanagia:20100226215915p:image

あそびかた

「動画を読み込む」ボタンを押すと、テキストボックスに入ってるurlの動画を読み込みます。「state」って書いてあるところが「stand by」になったら「再生 / 停止」ボタンを押してください。

あとは再生しながらスライダーを動かしたりすると、なんだか楽しい感じになります。

(※ Google Chromeだと透過度パラメータが反映されないようです。)


テキストボックスにはデフォルト

http://www.youtube.com/demo/google_main.mp4

を入れてますが、<video>タグで再生できるやつなら何でも大丈夫なはずです。適当にmp4なurlを探してきて遊んでみてください。


ウリ

HTML5 + JavaScriptのみの実装です。


作ってて思ったこと


「Webブラウザで動画編集」は幻想じゃない

HTML5とJavaScriptだけでも編集ソフト作れますね。今回はUIつけてませんが、カット編集もできます。アニメーションもできます。

作ってる最中は「パフォーマンス的に厳しいかな?」と思ってましたが、軽いコーデックの動画ならElisとほぼ同じ速度で動きます。

編集結果の書き出しは、連番画像をbase64で出力するとか、最終的なレンダリングサーバー側で行うとかすればできそうですね。


編集ソフトをWebアプリとして作る意味

編集ソフトがWebとつながることで、Webの資源に簡単にアクセスできるようになります。

今までローカルにファイルを保存しないとできなかった、「zoomeとニコニコの動画を使ってマッシュアップ」みたいなことがwebブラウザだけでできるようになります。

Flickrから画像を選んで、YouTubeから音楽を選んで、スライドショーの動画を作成」みたいなこともwebブラウザだけでできるようになります。

これってすごく面白いことだと思いませんか?


動画編集ソフトウェアを簡単に作れる時代がやってきた

今まで、動画を扱うソフトウェアを作るのはすごく面倒でした。

「よし作るか!」という気になっても、まずは画像処理、音声処理、動画処理、資源管理、描画処理、その他もろもろのライブラリとかフレームワークとかを探すところから始めないといけません。使うライブラリが決まったらライセンスに矛盾がないか確認して、リンクして、動かしてみて、「えっ、このフレームワークってGCと一緒に使えないの?」みたいなことがあったりして、とにかく面倒です。


でも、今ならHTML5とJavaScriptだけで動画を扱うソフトウェアを書けます。

もしあなたがJavaScriptプログラマなら、今すぐに動画を扱うソフトウェアを作ることができます。


面白い未来が、楽しい未来が、すぐそこまで来ている気がします。

2009-10-17

[] Youtubeに解説動画を上げていない理由

いろんなところで聞かれたので書いておきます。


Youtubeに動画を上げていない理由は以下の2つです。

  • まだα版(そこまでオープンにするつもりはない)
  • まだα版(10.6専用のはずなのに10.5で動く)

β版をリリースするタイミングできちんと紹介動画を作ればいいかなって思ってます。


追記

α版の「使い方動画」があって「紹介動画」が無い理由も同じ。その時点で大きくアピールするつもりがなかったから、紹介動画を作っていない。

2009-10-13

[][] Core Imageフィルタで平行移動がしたい

考えたけどできなかったという話。


Core Imageフィルタで平行移動がしたい

f:id:yanagia:20091013234438p:image

こういう画像から

f:id:yanagia:20091013234439p:image

こういう画像を作りたい。


フィルタでできると何がうれしいの?

平行移動した画像を別のフィルタの入力にできる。

普通に平行移動すると、

[ciContext drawImage:image atPoint:offset/* 平行移動 */ fromRect:contextRect];

こんな感じになっちゃって、平行移動済みの画像をあれこれできない。

glReadPixelsとかで読み戻せばできるけど、パフォーマンスがすごく悪くなる。


アフィン変換フィルタで平行移動できそう。でもできない。

CIAffineTransformっていう画像にアフィン変換を施すCore Imageフィルタがあるけど、これは拡大縮小と回転しかできない。


負の方向にクロップするとできそう。でもできない。

CICropフィルタの入力に負の値を与えるとそれっぽい画像を返してくれる。でもこっちが想定しているスケールにならない。


いちどNSImageに変換すればできる。

CIImageをNSImageとかに変換して平行移動してCIImageに戻せばできる。でもいちいちメインメモリに読み戻すのはパフォーマンス的にNG。


自分でCore Imageフィルタを書けばできる。

当たり前だけどできる。でも、よくよく考えたら処理にほとんど必要ないピクセルのためにVRAMを食いつぶすのはよくないよね。


わかったこと

Core Imageフィルタで平行移動しようとしてはいけない。

2009-10-09

ポメラ買ったよ!

前から欲しくて今日あきばお〜に行ったら1万5000円だったので買っちゃいました!

f:id:yanagia:20091009205247j:image

色はオレンジ! オレンジが似合う女の子ってかわいいよね!


これで僕も長文アウトプッターの仲間入りです!

2009-10-08

魔法少女リリカルなのは」のキャラクター登場率を集計してみる

A'sの再放送を見て、なのは面白いなあ、すずかかわいいなあ、やっぱり僕はなのはが好きなんだなあ、と思ったのでやってみました!


このエントリの目的

魔法少女リリカルなのはA's THE COMICSのキャラクター登場率を集計します。


集計ルール

例えばアリサ・バニングスを集計するときは、

  • コマにアリサが見えたら+1
  • アリサの台詞/モノローグがあったら+1

という感じで点数をつけます。「コマにアリサがいて更に喋っている」場合は+2です。各自持ち点0からスタート。


集計対象はReport1〜5。他はまだやっていません。


集計結果



Report 1 「高町なのはのある一日」

キャラクター名点数
高町なのは57
ユーノ・スクライア31
レイジングハート18
クロノ・ハラオウン18
フェイト・テスタロッサ13
エイミィ・リミエッタ12
リンディ・ハラオウン7
アリサ・バニングス3
月村すずか3

感想

一期の主役組、なのは・ユーノがトップ。この頃のユーノは輝いていた。劇場版でも輝いて欲しい。

レイジングハートも予想外に健闘。フェイトよりも露出が多いってどういうことなの。


Report2 「フェイト・テスタロッサ 試験を受ける」

キャラクター名点数
フェイト・テスタロッサ76
アルフ32
クロノ・ハラオウン28
レティ・ロウラン23
リンディ・ハラオウン10
バルディッシュ8
S2U4
高町なのは3

感想

エピソードの主役はやっぱり強い。フェイトとアルフだけで全体の6割。

クロノはそれなりだがレティはおかしい。

しかしバルディッシュは寡黙だなあ。


Report 3 「闇の書、八神はやてと騎士たちを想う」

キャラクター名点数
八神はやて44
闇の書40
シグナム32
ヴィータ31
シャマル27
ザフィーラ3

感想

僕はザフィーラ好きだよ。


Report 4 「アリサ・バニングスのスクールデイズ

キャラクター名点数
フェイト・テスタロッサ78
アリサ・バニングス66
高町なのは49
月村すずか36
エイミィ・リミエッタ17
アルフ11

感想

アリサが一位になれないこの集計方法は明らかに間違っていた。


点数的には負けてるけど、すずかの印象が薄いなんてことはない。ちゃんと見せ場があっていい感じ。

こういうともだちの話が僕は一番好き。

しかしアリサはかわいい。


Report 5 「八神はやて、現在の日々を思う」

キャラクター名点数
八神はやて77
シグナム37
シャマル34
月村すずか27
ヴィータ26
闇の書21
ザフィーラ7

感想

順当な順位。でも闇の書はもう少し自重していい。


まとめ

ぶっちゃけそこまで面白いデータは得られませんでした!


その他思ったこと

各話タイトルを眺めたら、なのはとフェイトとアリサとはやての名前は見つけられるのにすずかだけいない。

まあすずかはA's本編で主役やってるからね。しかたないね。

しかしアリサはかわいい。

2009-10-04

[] Elis Colors 0.2 をリリースしました

Elis Colors 0.2(alpha2) をリリースしました。


※今度こそLeopardでも動くはず。


0.1 (alpha1)からの変更点

  • プレビュー時のパフォーマンス向上
  • qtzファイルを30秒以上再生できなかったのを修正
  • 音声トラックのボリューム調整が可能に(キーフレームもOK)
  • メディア読み込みのチェックを厳格に(扱えないメディアは読めなくなったはず)
  • テキストレイヤーで画面サイズより大きなテキストが扱えるように

チュートリアル補足

  • 映像トラックは強制ミュートします。
  • 環境設定で「ハイパフォーマンスモード」をon/offできます。
  • Finderからタイムラインへメディアを直接ドロップしないください。
  • 動画の書き出し中にウィンドウサイズを変更しないでください。(最小化はOK)

注意点

  • At your own risk
  • Elis Colors 0.1とプロジェクトの互換性はありません。
  • 音声の書き出すとノイズが乗るかもしれません。

ダウンロード

http://eliscolors.sourceforge.jp/


ついでに

Elis Colorsリリース告知用のついったーBotをつくりました。

http://twitter.com/eliscolors