スペクトルをリアルに見せる (仮想データであろうとなかろうと) ための鍵は、バンド バーのフォールバック メカニズムを持つことです。
帯域は、新しい値が現在の値よりも高い場合にのみ設定されます。そうでない場合、現在の値は値 (線形または対数) だけ減少します。フォールバックの速度も認識に影響します。
スペクトル アナライザーのデータは実際の波形ではなく、FFT (高速フーリエ変換)、または各周波数帯域の値を表すため、ランダムなデータでも問題なく動作します。もちろん、音楽のように「リズミカルな」指紋は得られませんが、フォールバックがあるため、ある程度リアルに見えます(まるで誰かがノイズを聞きたいかのように:-))。
例は次のとおりです -
デモはこちら:
http://jsfiddle.net/AbdiasSoftware/VXxwt/
最初の HTML、単純な div:
<div id="logo"></div>
初期 CSS:
.band {
background-color: #3897e0;
border-radius:3px 3px 0 0;
}
そして、その仮想スペクトルを作成するための主な呼び出し:
makeSpectrum('logo', 300, 120, 7);
完全なコード:
/**
* Turn an element into a virtual spectrum,
* Ken Fyrstenberg Nilsen, Public domain.
*
* USAGE:
* makeSpectrum(id, width, height)
* makeSpectrum(id, width, height, bands)
* makeSpectrum(id, width, height, bands, volume)
*
* id id of the element to be converted into spectrum
* width width in pixels of spectrum
* height height in pixels of spectrum
* bands (optional) number of "bands"
* volume initial volume (0-1)
*
* METHODS:
*
* setVolume() returns current volume
* setVolume(vol) sets new volume (0-1 float)
*/
function makeSpectrum(id, width, height, bands, volume) {
bands = bands ? bands : 12;
volume = volume ? volume : 1;
if (bands < 1) bands = 1;
if (bands > 128) bands = 128;
// init parent element
var parent = document.getElementById(id),
bandElements = [];
if (typeof parent === 'undefined')
alert('Element ' +id + ' not found!');
parent.style.display = 'block';
parent.style.width = width + 'px';
parent.style.height = height + 'px';
parent.style.position = 'relative';
var bandValues = [],
oldBandValues = [],
bw = (((width)/ bands) |0),
me = this;
function calcBand(bandNum) {
var bv = bandValues[bandNum],
obv = oldBandValues[bandNum];
if (bv >= obv) obv = bv;
obv -= 0.1;
if (obv < 0 ) obv = 0;
obv *= volume;
oldBandValues[bandNum] = obv;
return obv;
}
function getFFT(band) {
band = band ? band : bandValues;
for(var i = 0; i < bands; i++) {
band[i] = Math.random();
}
}
function createBands() {
var i, html = '';
for(i = 0; i < bands; i++) {
h = 0
html += '<div id="' + id + '_band' + i + '" ';
html += 'style="display:block;position:absolute;';
html += 'left:' + ((i * bw + 1)|0);
html += 'px;top:' + ((height - height * h)|0);
html += 'px;width:' + (bw - 2);
html += 'px;height:' + ((height * h)|0);
html += 'px;" class="band"></div>';
}
parent.innerHTML = html;
for(i = 0; i < bands; i++) {
var el = document.getElementById(id + '_band' + i);
bandElements.push(el);
}
}
this.setVolume = function(vol) {
if (arguments.length === 0)
return volume;
if (vol < 0) vol = 0;
if (vol > 1) vol = 1;
volume = vol;
}
this.setVolume(volume);
this.createSnapshot = function() {
var h, y, el;
getFFT(bandValues);
for(var i = 0; i < bands; i++) {
h = calcBand(i);
el = bandElements[i].style;
el.top = ((height - height * h)|0) + 'px';
el.height = ((height * h)|0) + 'px';
}
parent.innerHTML = html;
}
//init bands
getFFT(oldBandValues);
createBands();
//GO
setInterval(me.createSnapshot, 100);
return this;
}
var sp = makeSpectrum('logo', 250, 100, null, 0);
var vol = 0;
function fadeIn() {
vol += 0.02;
sp.setVolume(vol);
if (vol < 1) setTimeout(fadeIn, 60);
}
fadeIn();
コードは最適化されていないため、CPU を少し消費します。これは主に、バンドの html が生成される方法です。はるかに効率的に動作するキャンバス要素でそれを行うことを好みますが、多数のブラウザーサポートが必要なため、これを残しました:-)
アップデート:
キャッシュされた要素のループ設定の高さと上部を最適化しました。setVolume()
また、ループなどから全体の「音量」を設定するために使用できるメソッドもあります。
例 (上部のリンク) をフェードインと新しいコードで更新しました。
更新 2:
内部クロックに基づいて BPM をシミュレートすることにより、より低い周波数でよりリアリズムを追加しました。ここで、時間が最初の 3 つのバンドに影響するようにします (バンドの数が許す場合)。
var d = (new Date()).getMilliseconds() % 10; //get milliseonds of second
band[0] = band[0] * 0.2 + (d / 10) * 0.8; //affect 1. band 80% + 20% random
band[1] = band[1] * 0.3 + (d / 10) * 0.7; //affect 2. band 70% + 30% random
band[2] = band[2] * 0.5 + (d / 10) * 0.5; //affect 3. band 50% + 50% random
微妙かもしれませんが、もう少しリアリズムを追加するだけです.
ミュート機能を備えたスタイル バージョン:
http://jsfiddle.net/AbdiasSoftware/hVkPN/