RICOH THETAとJavaScriptでハコスコ用コンテンツを作るの巻

ハコスコは、iPhoneさえあればわずか1000円で実現できてしまうヘッドマウントディスプレイです。ただまだ視聴できるコンテンツがそれほど多くありません。
 
そんなわけで今回はRICOH THETAを使ってハコスコ用のコンテンツを自作してしまおうという企画です。
 

 
THETA用オレオレビューアライブラリthview.jsを最近アップデートしました。iPhoneの加速度センサーの情報を見て傾きに合わせて全天球画像を表示します。HTMLとJavaScriptだけなので、本格的な開発環境は不要でテキストエディタとウェブサーバだけあれば誰でも作れます。
WebGLの関係上、iOSのバージョンは8にする必要があります。
 
デモ1 戸棚の中

f:id:aike:20140930214741p:image

 
HTML的にはこんな感じです。

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title></title>
    <script type="text/javascript" src="three.min.js"></script>
    <script type="text/javascript" src="thview.js"></script>
</head>
<body>
    <div id="image1" style="position:absolute;top:0px;left:0px;"></div>
    <script type="text/javascript" >
        var img1 = new ThView({
            id:'image1',
            file: 'images/photo.jpg',
            width: 980,
            height: 560,
            zoom: 100,
            firstview: 90
        });
    </script>
</body>
</html>

 
また、THETAの公式アプリは最近のアップデートで、一定時間ごとに自動的にシャッターを切るインターバル撮影機能がつきました。そのためthview.jsにも連続写真をパラパラマンガ風に表示する機能をつけました。
 
デモ2 連続写真

f:id:aike:20140930214742p:image

 

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title></title>
    <script type="text/javascript" src="three.min.js"></script>
    <script type="text/javascript" src="thview.js"></script>
</head>
<body>
    <div id="image1" style="position:absolute;top:0px;left:0px;"></div>
    <script type="text/javascript" >
        var img1 = new ThView({
            id:'image1',
            file: [
                'images/R0010155.JPG',
                'images/R0010156.JPG',
                'images/R0010157.JPG',
                     :(省略)
                'images/R0010175.JPG'
            ],
            interval: 500,
            width: 980,
            height: 560,
            firstview: -90
        });
    </script>
</body>
</html>

画像はiPhoneのCPUパワー等を考慮して元画像よりも少し小さくした方が良いようです。
 
Oculus Riftみたいに両目で別々の画像を見る方が良いのかもと思ってthview.jsに hmd: true というオプションも用意しましたが、ハコスコの場合は両目で同じ画像を見るのがよさそうでした。
 
デモ3 両目別画像

f:id:aike:20140930214743p:image

 
Enjoy!
 

ハコスコ

ハコスコ

IR録ろうぜ!2

DTMでよく使われるコンボリューションリバーブやアンプシミュレーターは、現実世界の音響的特徴をWAVファイルのかたちに記録したIR(Impulse Response、インパルス応答)を使って周波数特性や残響をシミュレートします。
 
最近はWeb Audio APIにもコンボルバーがあるので、気軽にIRを使える環境も広がってきたように思います。
 
IRファイルはDTMソフトウェアに付属するものから出自の怪しいものまでいろいろありますが、安心して自由に使えて再配布可能なものとなると意外と少なかったりします。
 
そんなわけで、IRファイルを自作してしまおうというのが今回の主旨です。
 
実はかなり前にプラグインエフェクトからIRを録る手順についてブログに書いたことがあります。今回は実際のアンプからマイク録りしてIRを作ります。
 

 
音響工学的な正確さを求めなければ、すごく簡単に作れるのがわかると思います。
 
このとき作ったIRファイルがこちらです。
ir_impulse.wav
ir_sweep.wav
 
これらをギターの音にかけてみます。
 
これが元のギターの音。かなりライン録りくさい感じがします。
Download
 
クラップ音から作ったIRをかけた音。なんだかちょっとクセのある音ですがアンプっぽくなりました。手を叩いた時の残響が混ざって少しルームリバーブがかかったような音になっています。
Download
 
スイープ音から作ったIRをかけた音。小型アンプとはいえマーシャルの特徴がけっこう出てると思いませんか。
Download
 
IRはそれ自体がWAVなのでIRの波形を加工して残響成分を増減したりEQをかけて整えたりすることもできます。
また、本来IR目的ではない音のWAVファイルをIRとして使って特殊な音を作るようなクリエイティブな方法もあるので自由な発想でいろいろ試してみてください。

ブラウザでVJプログラム書くときのフレームワーク作った

JavaScriptでオーディオとビジュアルの扱い方をおぼえると、人類はみなVJアプリを作るようになります。ぼくの周りの5人くらいの人類はそうでした。
 
自分もいろいろビジュアライザーアプリを作ってイベントでブラウザVJやったりしました。ただ、ひとつひとつはそれなりに面白い視覚効果のプログラムでも、それだけでは長時間のイベントに対応できません。通常のVJのように、イベントの進行やDJの音楽の緩急に合わせて効果的な視覚効果を選択して次々と切り替えていきたいところです。
 
そんなわけで、複数の視覚効果をクロスフェードで切り替えられるようなブラウザVJフレームワークを作りました。それぞれの視覚効果や各種の機能をプラグインとして仕様化し、この仕様に合わせれば拡張機能プラグインを自作できるようになっています。
  
https://github.com/aike/jsdrome
http://aikelab.net/jsdrome/
 

 
■仕様
・複数のビジュアライザーをプラグインとして組み込み
・ビジュアライザー同士のクロスフェード
・非表示状態のビジュアライザーの処理を自動停止
サウンドファイルの再生
・マイク入力またはサウンドファイルに反応する映像処理
・テキストロゴ表示
・ウェブカメラ入力表示
・キーボード入力による制御
MIDI入力による制御
Leap Motion入力による制御
 
現状、以下のようなビジュアライザープラグインがあり、クロスフェードで切り替えられます。

3d-cube.js キューブ
3d-wave.js スペクトラムアナライザ
3d-lissajous.js リサジュー図形
3d-matrix.js マトリックス
3d-stardust.js 宇宙
danmaku.js 弾幕ビジュアライザー
videoplayer.js 動画プレイヤー
dummy.js 表示テスト

 
以下のプラグインクロスフェードせずに常時有効となる共通プラグインです。

common/logo.js テキストロゴ表示
common/musicplayer.js 音楽プレイヤー
common/camera.js Webカメラ+エフェクト
common/controlwindow.js 操作パネル表示
common/leap.js Leap Motionインタフェース

 
プラグインは以下の各イベントに対応するメソッドを実装します。イベント処理が不要の場合は空のメソッドとしておきます。

onStart() 表示開始
onStop() 表示終了
onFade(opacity) フェードイン/アウト処理 opacityは0〜1
onAudio(moment, period) マイク入力またはオーディオファイルの音量が定期的に通知される
onKeydown(keycode) キー押下イベント。フォアグラウンドのプラグインにのみ通知される
onResize(x, y, width, height) ウィンドウリサイズ処理
onTimer() 描画用タイマーイベント
onMidi(arg1, arg2, arg3) MIDI入力イベント

 
わりと多機能なので、いずれもう少し詳しく書く予定です。

Webでポリシンセ作るときのテンプレ作った

もう半年以上前に作ったやつですけどせっかくなので解説。
 
JavaScriptでプログラミングをやっていると人は誰しもシンセを作りたくなるかと思います。僕も3年くらい前にWeb Audio Synthというのを作りました。
 
いまはウェブブラウザもオーディオやMIDIAPIが充実してきてシンプルな単音のシンセを作るのは簡単になりました。でもちょっと和音を弾きたくなってポリシンセに拡張しようと思うとこれがけっこう大変だったりします。
同時発音数6ボイスのポリシンセを作るとなったら、ほんとうにモノシンセを6個分実装する必要があります。さらに、和音を弾いている最中に追加で音を重ねるときなど空いているボイスをさがして割り当てるといったオブジェクトプーリングの仕組みが必要になります。
また、いくつかシンセを作っていると、鍵盤のUIやMIDI入力の対応など定型的で毎回同じ作業があることに気づいてきます。
 
そんなわけで、そういった部分をテンプレ的に用意しました。つまり、ボイス(ノートナンバーに応じて単音を生成する処理)の中身を自作すれば、それ以外の和音の処理、鍵盤のUI、ASCIIキーボードイベント処理、MIDIイベント処理、WebMidiLinkイベント処理などはテンプレにまかせてしまえるというものです。

https://github.com/aike/TemplateSynth

 
■シンセの作成例
自分のシンセを作りたい時は js/voice.js を拡張するようにしてください。

メソッド名 処理内容
Voice#noteOn(note, velocity) 発音開始
Voice#changeNote(note) 発音中に音程変更
Voice#noteOff() 発音終了
Voice#setParam(param_id, val) パラメータ設定(空でも可)

 
デフォルトではサイン波を鳴らすシンセになっています。

var Voice = function(ctx) {
	this.ctx = ctx;
	this.next_node = null;
	this.noteNoToFrequency = function(noteno) {
		return 440.0 * Math.pow(2.0, (noteno - 69.0) / 12.0); 
	}
}

Voice.prototype.noteOn = function(note, velocity) {
	this.osc = this.ctx.createOscillator();
	this.osc.frequency.value = this.noteNoToFrequency(note);
	this.osc.connect(this.next_node);
	this.osc.start(0);
}

 
こんな風に変えるとプレイバックサンプラーになります。

var Voice = function(ctx) {
	this.ctx = ctx;
	this.next_node = null;
	this.noteNoToSpeed = function(noteno) {
		return Math.pow(2.0, (noteno - 69.0) / 12.0); 
	}
	var self = this;
	this.loadwav('sampler.wav', function(buf) { self.buf = buf; });
}

Voice.prototype.loadwav = function(file, callback) {
	var xhr = new XMLHttpRequest();
	xhr.open("GET", file, true);
	xhr.responseType = "arraybuffer";
	var self = this;
	xhr.onload = function() {
		self.ctx.decodeAudioData(xhr.response,function(buf){
			callback(buf);
		}, function(){});
	};
	xhr.send();
}

Voice.prototype.noteOn = function(note, velocity) {
	this.sample = this.ctx.createBufferSource();
	this.sample.buffer = this.buf;
	this.sample.playbackRate.value = this.noteNoToSpeed(note);
	this.sample.connect(this.next_node);
	this.sample.start(0);
}

 
1ボイスにつきデチューンした5個のノコギリ波を鳴らすSuper Saw的なシンセならこんな感じ。

var Voice = function(ctx) {
	this.ctx = ctx;
	this.next_node = null;
	this.noteNoToFrequency = function(noteno) {
		return 440.0 * Math.pow(2.0, (noteno - 69.0) / 12.0); 
	}
	this.osc = new Array(5);
	this.gain = new Array(5);
	for (var i = 0; i < 5; i++) {
		this.gain[i] = this.ctx.createGain();
		this.gain[i].gain.value = 0.3;
	}
}

Voice.prototype.noteOn = function(note, velocity) {
	for (var i = 0; i < 5; i++) {
		this.osc[i] = this.ctx.createOscillator();
		this.osc[i].type = 'sawtooth';
		this.osc[i].detune.value = 10 * i - 20;
		this.osc[i].frequency.value = this.noteNoToFrequency(note);
		this.osc[i].connect(this.gain[i]);
		this.osc[i].start(0);
	}
}

 
最大同時発音数は synth.js で以下のように指定しています。

synth = new Synth(8);

 
MIDI鍵盤から演奏したり、ASCIIキーボードを鍵盤代わりに弾くこともできます。
シンセの発音アルゴリズムを試したりするのに便利なので使ってみてください。
Web Componentsとか使ってるので動作環境は現状Chromeのみだと思います。

全天球ビューワーPaView.jsの動作環境とパノラマ飛行動画

先日作った全天球ビューワーPaView.jsですが、できるだけ多くのブラウザで表示できるよう調べてみました。
クロスブラウザで問題になるところは、マウスイベント、WebGLで動画のテクスチャマッピングしているところ、対応動画フォーマットあたりです。
 
Windows
Windows PCのブラウザは素直なものが多いようで、マウスイベントの処理をブラウザごとに書くくらいで、わりとそのまま動きました。Windows7上のChromeFirefoxIEで正常に動くことを確認しました。
 
Mac OS
Macの場合、Safari用のマウスイベント処理を書いたら正常に動きました。Firefoxは.mp4の動画に対応しておらず(特許関係らしいです)、WebMで表示するようにしてみました。サーバ上に.mp4と同名の.webmのファイルを用意しておけば、.mp4を.webmとJSが読み替えて無理矢理表示します。サーバ側も AddType video/webm .webm する必要があるかもしれません。
OS X Mavericks上のChromeFirefoxSafariで正常に動くことを確認しました。
 
iOS
iOSはWebGLRendererが使えないっぽいのでテクスチャマッピングがうまくいかず非対応です。
 
Android
Androidは持っていないので未確認です。たぶんiOSと同じような状況だと思います。
 
先日、メディアアーティストの八谷さんの超小型飛行機にカメラを搭載して撮影した動画をアップしました。空中を飛んでいる風景は全天球パノラマ動画の大きな可能性を感じることができると思います。見てみてください。
 
http://sound.jp/aike/m02j/

f:id:aike:20140824184126p:image:w640

※音が出ます。レンタルサーバの仕様上MacFirefoxには対応していません。

MMDの全天球パノラマ動画を作ってみた

THETAからはじまって最近は動画にいたるまで、このところ全天球パノラマに興味を持っていたところ、先日こんなツイートを見かけました。
 

 
通常、全天球パノラマ動画は6台のGoProで実写撮影した動画を、専用のスティッチングソフトを使って手作業で合成していきます。MMDの場合最初から仮想空間のCGなので、わざわざ6本のムービーとして出力して再合成する意味はあんまりないのですが、スティッチングの練習になりそうだし面白そうなのでやってみました。
 
http://sound.jp/aike/paview/index6.html

f:id:aike:20140807183650g:image

FL-chan−TYPEアノマロ モデル by アノマロかりんとう / 金剛八式 モーション by hino / 鷲宮神社 ステージ by リボン犬
 
上のリンク先へ行くと、マウスでカメラを好きな方向に向けられる全天球パノラマ動画が表示されます(上記はキャプチャしたGIFアニメ)。一見リアルタイムレンダリングの3DCGのようにも見えますが、実際はムービーなのでFLちゃんの向こう側を見たりはできません。
 
MMDの出力パラメータはこんな感じです。
出力サイズ:
 640 x 480 px
視野角:
 100
カメラ角度:
 cam1 0, 0, 0
 cam2 0, 180, 0
 cam3 0, 90, -90
 cam4 0, -90, 90
 cam5 90, 180, 90
 cam6 -90, 180, 90

ブラウザで波紋エフェクト出すやつ作った

最近プレゼンとかでウェブベースのアプリを実演する機会がわりとあったりします。そのときちょっと不便なのは、マウスをどのように操作して、どこでどういう風にクリックしたのかがいまいち伝わりにくいということで。まあしょうがないかと思ってたんですが。
 
そうしたら次期Androidマテリアルデザインでは波紋エフェクトが使われるようになるとか。あー、その手があったか。そういえば、スマホじゃなくてPCの世界ではそういうのときどき見たことあるな、と思ってJavaScriptで作ってみました。
 
http://aikelab.net/visibletouch/
https://github.com/aike/VisibleTouch.js
 

f:id:aike:20140806180238g:image

 
発想の元はマテリアルデザインの波紋エフェクトですが、プレゼン用ということで最終的にいろいろ違った感じになりました。たぶん探せば同じようなツールはすでにたくさんあって101回目くらいの車輪の再発明だとは思うけど、自分用にぴったりのがほしかったので自作しました。
 
ライブラリのJSファイルは共通部と固有部にわかれていて、読み込む固有ライブラリによってビジュアライズが変わります。
 
visibletouch.js 共通ライブラリ
visibletouchripple.js 固有ライブラリ:波紋エフェクト
visibletouchmouse.js 固有ライブラリ:マウスイラスト表示
visibletouchano.js 固有ライブラリ:「あの楽器」風 波紋エフェクト
 

f:id:aike:20140806180607g:image

 
波紋エフェクトの仕組みとしては、ウィンドウと同じサイズの透明なキャンバスをあらかじめ最下位レイヤーに置いておいて、クリックされたらキャンバスを最上位レイヤーに移動して波紋アニメーションを描画。波紋が完全にフェードアウトしたら再びキャンバスを最下位レイヤーに戻す、という無理矢理なことをしています。そのため波紋描画中に連続してクリックしたりドラッグしたりすると、いろいろ悲しい思いをすることがあると思います。
 


Invisible Touch

Invisible Touch