使频谱看起来真实(虚拟数据与否)的关键是为波段栏提供后备机制。
仅当新值高于当前值时才设置波段。如果不是,则当前值减少一个值(线性或对数)。回退的速度也会影响感知。
由于频谱分析仪中的数据不代表实际波形,而是 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,在较低频率中增加了更多的真实感。我现在让时间影响前三个频段(如果频段数量允许):
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/