如何生成模拟音频信号的随机数据?

Jas*_*ske 9 javascript audio jquery html5

我正在开发一个动画徽标,将由零到十一的频谱分析仪显示出来.我正在寻找可以在各种浏览器上运行的东西,所以将它连接到HTML5音频元素可能不是一个选项,因为我发现只能在最新的WebKit和Firefox上工作的唯一库版本.到目前为止,我一直在玩一个间隔生成一个随机值.这是我目前陷入困境的一个例子(使用jQuery的animate函数()):

<div id='Logo'>
    <div id='channelA' class='channel'></div>
    <div id='channelB' class='channel'></div>
    <div id='channelC' class='channel'></div>
    <div id='channelD' class='channel'></div>
    <div id='channelE' class='channel'></div>
    <div id='channelF' class='channel'></div>
    <div id='channelG' class='channel'></div>
</div>
<script>
  setInterval(function () {
    $('.channel').each(function () {
        $(this).animate({
            height: (Math.round(Math.random() * 185)) + 'px'
        });
    });
  }, 100);
</script>
<style>
#Logo {
    width: 245px;
    height: 245px;
    background: red;
}
div.channel {
    float: left;
    z-index: 9;
    background: white;
}
#channelA {
    width: 35px;
    height: 45px;
}
#channelB {
    width: 35px;
    height: 85px;
}
#channelC {
    width: 35px;
    height: 85px;
}
#channelD {
    width: 35px;
    height: 50px;
}
#channelE {
    width: 35px;
    height: 150px;
}
#channelF {
    width: 35px;
    height: 30px;
}
#channelG {
    width: 35px;
    height: 85px;
}
</style>
Run Code Online (Sandbox Code Playgroud)

这看起来并不"正确".是否有能够生成"感觉"更像音频信号的数据的功能?我也对这个问题的其他方法感兴趣(也许我只需要在支持HTML5音频的浏览器中捕获频谱分析仪数据,然后在旧浏览器中"回放".)

这是我想要的样子的一个例子:

在此输入图像描述

在JavaScript中搜索Bézier曲线的一些实现后,我开始混合生成的单曲来制作一些东西.虽然我未完成的工作,如果这给了其他人任何想法,这是一个演示.

小智 8

使频谱看起来真实(关键是否是虚拟数据)的关键是为频段提供回退机制.

仅当新值高于当前值时才设置波段.如果不是,则将当前值减小一个值(线性或对数).后退的速度也会影响感知.

由于频谱分析仪中的数据不代表实际波形,而是FFT(快速傅立叶变换)或每个频带的值,因此它可以与随机数据一起正常工作.你当然不会得到音乐的"节奏"指纹,但由于有后退,它在某种程度上仍然看起来很逼真(好像有人想听听噪音:-)).

以下是一个例子 -

快照

演示:http:
//jsfiddle.net/AbdiasSoftware/VXxwt/

最初的HTML,一个简单的div:

<div id="logo"></div>
Run Code Online (Sandbox Code Playgroud)

初始CSS:

.band {
    background-color: #3897e0;
    border-radius:3px 3px 0 0;
}
Run Code Online (Sandbox Code Playgroud)

并且主要要求创建一个虚拟频谱:

makeSpectrum('logo', 300, 120, 7);
Run Code Online (Sandbox Code Playgroud)

完整代码:

/**
 *    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();
Run Code Online (Sandbox Code Playgroud)

代码没有优化,所以它在CPU上运行有点饿.它主要是为乐队生成html的方式.我更喜欢做哪会工作更加高效canvas元素,但由于需要的浏览器支持多种我离开这个:-)

更新:

优化了循环设置高度和缓存元素的顶部.它还有一个方法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
Run Code Online (Sandbox Code Playgroud)

这可能是微妙的,但只是为了增加一点现实主义.

这里的样式版本具有静音功能:http:
//jsfiddle.net/AbdiasSoftware/hVkPN/

款式版

  • 这个解决方案看起来非常逼真 - 令人印象深刻 (2认同)