« 2014年11月 | 2014年12月のアーカイブ | 2015年01月 »
2014/12/29
Base64/Base64Url エンコーダー/デコーダー
なんかBase64/Base64Urlのエンコーダー、デコーダーを必要になる度に書き直している気がする。探せばいくらでもある事はあるし、毎回書いても大した事ないと言えばないのだけど、それなりに面倒なのでここに割と潰しが効きそうな感じの奴を置いておく事にします。
エンコーダーの方は文字列でもバイト配列でも受け付けて第2引数にtrueを渡すとBase64Urlになります。デコーダーの方は入力は文字列でBase64/Base64Urlのどちらでもデコードでき、第2引数にtrueを渡すと出力が文字列、省力するとバイト配列で戻します。 頑張ればもうちょっと短くなるかも知れないけど、これくらいなら満足かなぁ
WTFPL(Do What The Fuck You Want To Public License) v2 ライセンス : http://www.wtfpl.net
//Licensed under WTFPLv2
function EncBase64(x,base64url){
var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
var r = "", d = 0, bits = 0, l = x.length, get = function(i){return x[i]};
if(base64url)
tab = tab.replace("+/","-_");
if(typeof(x) == "string")
get = function(i){return x.charCodeAt(i);};
for(var i = 0; (i < l) || bits; ++i){
d <<= 1,++bits;
if(i < l)
d = (d << 7) + (get(i) & 0xff), bits += 7;
while(bits >= 6)
r += tab[(d >> (bits -= 6)) & 0x3f];
}
if(!base64url)
r += "===".substr(0,((r.length + 3) & ~3) - r.length);
return r;
}
function DecBase64(x,str){
x = x.split("=")[0];
var tab = "-_ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
var r = [], d = 0, bits = 0, l = x.length;
for(var i = 0; i < l; ++i){
d=(d << 6) + ((tab.indexOf(x[i]) - 2) & 0x3f);
if((bits += 6) >= 8)
r.push((d >> (bits -= 8)) & 0xff);
}
if(str)
r = String.fromCharCode.apply(null,r);
return r;
}
※いや、これ、atob()/btoa()が動かない環境がまだあるとばっかり思っていたので作ったのだけど、今の最新のブラウザはどれもatob()/btoa()をサポートしてるんですね orz。ただまあBase64Urlをatob/btoaでやるにはパディングの処理とか文字の置換が必要なのでその辺だけ前後処理が必要になります。後はデコード結果を直接配列で取りたい時とかは使えるかも。まったく無意味という訳でもないので許してください。
posted by g200kg : 3:43 PM : PermaLink
2014/12/25
WebAudioAPIのPeriodicWaveを波形テーブルから使う
Web Audio APIのオシレータのカスタム波形の使い方についての話です。
Web Audio APIのオシレータにはサイン波や鋸歯状波などの基本波形以外にカスタム波形というモードがあります。これを使うと自由な波形を設定できるのですが、ある意味便利、ある意味厄介な事にこの設定が通常の波形の形を指定するのではなく、倍音構成を表すPeriodicWaveと言うテーブルで指定するという仕様になっています。
Web Audio API (日本語訳) : createPeriodicWaveメソッド
オルガンのドローバーのようなものを作るには直接このテーブルの値をいじれば良いので結構音楽的ではあるのですが、逆にチップチューン的なアプリで出力波形を直接指定したい場合にはどうすれば良いのでしょうか。
このPeriodicWaveテーブルは各倍音の強さを表し、
[波形] =フーリエ変換=> [PeriodicWave] => [Oscillator] => [波形]
という関係になりますので、出したい波形をフーリエ変換する事で必要なPeriodicWaveテーブルを得る事ができます。無駄な処理をしているような気もしますが、それが仕様なので諦めましょう。
という事でフーリエ変換? と言えばFFT? どこかにライブラリあるかな? という方向に行くのも良いのですが、FFTというのはフーリエ変換の特殊な計算省略方法でしかないので、FFTなんか使わずにまともにフーリエ変換するという道もあります。
と言われてもなぁ、と思うかも知れませんが、まともなフーリエ変換なんて下の関数程度の話です。
function fourier(waveform,len){
var real=new Float32Array(len),imag=new Float32Array(len);
var wavlen=waveform.length;
for(var i = 0; i < len; ++i){
for(var j = 0; j < len; ++j){
var wavj = j / len * wavlen;
var d = waveform[wavj|0];
var th = i * j / len * 2 * Math.PI;
real[i] += Math.cos(th) * d;
imag[i] += Math.sin(th) * d;
}
}
return [real,imag];
}
なお、入力の波形は補間はせず、6-7行目あたりで階段状の波形として処理していますが、必要ならここで線形補間などを入れても良いと思います。また、振幅方向は何もスケーリングしていませんがオシレータが勝手に正規化しますので、入力するテーブルは-1~+1でも0~100でも何でもよくて各値の比率だけが重要です。出力にはreal[0]の所にDCオフセットが出てきますが、ChromeのオシレータはDCオフセットは無視します(これが仕様なのかどうかは今一明確ではありません)。気になるならreal[0]を0にしてDCオフセットを潰しておいた方が良いかも知れません。
この方法の良い所はFFTと違って変換の入出力の長さが2の累乗じゃなくても良い所で、自分が欲しい長さだけを計算する事ができます。
もちろん不利な点としてはテーブルが長くなると計算量が爆発的に多くなる所で、数K単位の長いテーブルを使いたいとか、頻繁にテーブルを作り直したいとか、他の所で既にFFTを使っているとかいう場合にはFFTを使った方が良いかも知れませんが、せいぜい数100要素程度の長さのテーブルを設定を変えた時だけ計算し直したい、というような場合にはわざわざ大きなFFTライブラリなんかを持ち込まないというのもありかなと思います。
これを使ったサンプルプログラムを下に置いてありますので触ってみてください。
http://www.g200kg.com/demo/test/fourier.html
posted by g200kg : 6:00 AM : PermaLink
2014/12/23
WebGLデモに音を付けるあれこれ
この記事は「WebGL Advent Calendar 2014」23日目の記事です。
WebGL Advent Calendar 2014WebGLのアドベントカレンダーですが、音関係のお話です。
と言うかですね、音を扱うためのWeb Audio APIという強力なツールがブラウザ上でサポートされつつありますので、WebGLでイケてるデモを作ったら是非音も付けてみて欲しいな、と思うわけです。昔から音と映像は切っても切れない関係で、両方が揃うとインパクト倍増ですからね。
という事で、この記事では映像は出来たけど音をどうやって付けるか? というあたりのあれこれについての紹介です。
ブラウザのサポート状況
ブラウザ上で音を自由自在に扱えるという「Web Audio API」ですが、ブラウザサポート状況はまだまだ道半ばで、フルにガシガシ使うにはブラウザを限定する必要があります。今現在の各ブラウザのサポート状況は下の表のような感じです。Chrome | 最もサポートが進んでおり、リファレンスとなっています |
Safari | YosemiteでかなりChromeに近くなりましたが、一部挙動が異なります。それ以前のものはAPIが古い仕様になっていたりします |
Firefox | 一通りAPIがサポートされた所ですが、まだ挙動が安定しない事が割とよくあります |
IE | 開発に着手した事がアナウンスされましたが、まだ出てきていません |
いやもうmp3やらoggやらで裏で鳴らしたい音も出来上がってます、という場合、別にややこしい事はしないで<audio>タグで埋め込むだけでいいですね。と言っては身も蓋もないですが、今の所単純に準備済みのBGMをどの環境でも同じように鳴らしたいという話なら<audio>タグを使うのが有力です。これなら大体どのブラウザでも最新のものを使えば対応しています。ただ、これだと映像と音はそれぞれ勝手に走っているだけなので相互作用的なものを作るのは困難です。各ブラウザ共開発は進みつつありますので今後に期待しましょう。
なお、<audio>タグを使った埋め込みでもWeb Audio APIと連携させる事で相互作用を作る事も可能です。Web Audio APIの全貌をちゃんと知りたいという方はこちらをどうぞ。仕様の日本語訳とか解説を置いてあります。
Web Audio API 日本語訳
Web Audio API 解説
AutoBeats
とりあえずお手軽に音を鳴らす方法としてAutoBeatsというものをご紹介します。https://github.com/g200kg/AutoBeats
<audio>タグで楽曲を埋め込むにしても、権利関係の問題は結構厄介ですね。WebGLベースでちょっとしたデモを作ろうとしても流石に曲を作る所まで手が回らないという人も多いかと思います。AutoBeatsはいわゆる自動作曲でタイトルを設定するだけで勝手に曲のようなものを演奏しますので手軽に音を付けたいという場合には向いているかと思います。使い方は単純で、まず、autobeats.jsを読み込みます。polymer版もありますが、単にJavaScriptで使うだけならファイルとしてはautobeats.jsだけあれば良いです。
<script src="autobeats.js"></script>
beats = new AutoBeats("song title");
beats.start();
サンプルはここにあります。このページで「title」を色々書き換えてみてください。
AutoBeatsサンプル
音と映像の相互作用
さて、これで音を付ける事ができましたが映像と音は相互に作用してこそ威力を発揮します。ここでは音に合わせて映像が変化するビジュアライザー的なものの作り方を紹介します。Web Audio APIにはビジュアライザーなどに使えるAnalyserノードというものがあるのでこれを利用します。AutoBeatsは単体で勝手に音を出しますが音を出力先を指定できるようになっていますので、ここにAnalyserを接続します。audioctx=new AudioContext();
analyser=audioctx.createAnalyser();
analyser.connect(audioctx.destination);
beats=new AutoBeats("song title",0,audioctx,analyser);
beats.start();
[AutoBeats] => [Analyser] => [AudioContext.destination]
こういう繋ぎになります。
音のデータの取り出し方はこのanalyserのgetByteTimeDomainData()を呼び出せば波形そのままのデータ、getFrequencyData()を呼び出せばスペクトラムデータになります。引数には適当な長さのUint8Arrayを渡せば配列を埋めてくれます。後はこれを表示に反映するだけですね。
シェーダーで使うのでしたら、一度canvasのimgdatに落としてTexture2D経由で受け渡しするのが一般的かと思います。
x=window.innerWidth;
y=window.innerHeight;
wavdat=new Uint8Array(256);
wavimgdat=document.createElement("canvas").getContext("2d").createImageData(256,1);
z=Date.now();
(function(){
analyser.getByteTimeDomainData(wavdat); //波形データの取得
//analyser.getByteFrequencyData(wavdat); //こっちを使うとスペクトラムデータ
for(var i=0;i<256;++i) {
var j=i<<2;
wavimgdat.data[j]=wavdat[i];
wavimgdat.data[j+3]=255;
}
gl.clear(gl.COLOR_BUFFER_BIT);
gl.uniform1f(u.t,(Date.now()-z)*0.001);//<==経過時間(msec)
gl.uniform2fv(u.r,[x,y]);//<==画面のレゾリューション
gl.uniform1i(u.wav,0);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, wavimgdat);//<==音データ
gl.drawArrays(gl.TRIANGLE_STRIP,0,4);
gl.flush();
requestAnimationFrame(arguments.callee);
})();
ここでは渡された256 x 1のテクスチャーwavを
vec2 p=(gl_FragCoord.xy*2.-reso)/reso;
vec4 v=texture2D(wav,vec2((p.x+1.)*.5,0.));
で読み出し、
vec3 wave(vec2 p,float v){ float l=p.y-v;
float r=pow(max(0.,1.-distance(p+vec2(0.,+.5),vec2(p.x,v))),10.0);
return vec3(r,r*r,0.);
}
みなさんご存じのGLSL sandboxなんかでぐりぐり動くデモでもインプットとなる情報は時間とマウス座標くらいですけど、ここに音データが加わるとまた表現の幅が広くなりますね。
Planets
posted by g200kg : 9:15 AM : PermaLink
2014/12/06
WebAudioDesignerでボコーダーボイスを作る
一応WebAudioAPIのノードの繋ぎだけでボコーダーっぽい音を出しています。
見ての通り結構大変な事になっていますが、入力音声を6分割してエンベロープを取り出し、再合成しているだけです。
本来ならキャリア側にもフィルターバンクを入れて分解して変調する所ですが、さすがに溢れそうなのでサイン波を加算する感じになっています。
何が溢れるかというとグラフのデータをURL化してるのが長くなりすぎます。ブラウザの限界はもうちょっと行けそうなんだけどgithub上で動かしてる関係でどうやらURLの長さは4Kが限界の模様。
Vocoder voice on WebAudioDesigner
posted by g200kg : 9:42 PM : PermaLink
KDJ-ONEキックスターター開始記念
12月5日、一部で話題になっているKDJ-ONEという機材のクラウドファンディング KickStarter/IndieGogoでの支援募集開始記念お披露目会がありましたのでお邪魔してきました。
仕様の詳細等はこちらをどうぞ
http://www.kdj-one.jp/
またKickStarter/IndieGogoでの募集という事で、慣れていない方にはちょっと敷居が高いかも知れませんが、「DTMステーション」さんで凄く親切な手順のマニュアルを書かれていますのでそちらを見ながらどうぞ。今なら早期割引があって$395+(送料$10)になっています。
「DTMステーション:英語サイトでも大丈夫!KDJ-ONE購入手順完全マニュアル」
posted by g200kg : 11:36 AM : PermaLink
2014/12/02
WebAudioDesignerにツマミを付ける
WebAudioDesignerでツマミからパラメータをコントロールできるようになりました。
簡単なシンセくらいならGUI上でさくっと作れるようにしたいんだけど、まだ色々足りません。でもWebAudioAPIでどんな事ができるのか把握してもらうには良いツールになるんじゃないかなあ。
posted by g200kg : 12:01 PM : PermaLink
2014/12/01
第14回アナログシンセ・ビルダーズ・サミット
11月29日科学技術館で開催されたアナログシンセ・ビルダーズ・サミットに出展してきました。私が出したのは今更のGemBox Synth/Frisk SynthとLiveBeatsだったのですが、今年もなかなか興味深い話が色々聞けました。
私はこの3年ほどの様子しか知らないのですが、アナログシンセ・ビルダーズ・サミットももう14回目なんですね。運営ほんとうにご苦労様です。という事で濃すぎる年末イベントは終了しました。
posted by g200kg : 6:00 AM : PermaLink
« 2014年11月 | 2014年12月のアーカイブ | 2015年01月 »
-->
g200kg