9

私は、0 から 11 までのスペクトル アナライザーによって表示される、アニメーション化されたロゴに取り組んでいます。さまざまなブラウザーで動作するものを探しているので、最新の WebKit と Firefox でのみこの動作を実行できる唯一のライブラリを見つけたので、HTML5 オーディオ要素に接続することはおそらくオプションではありませんリリースします。これまでのところ、間隔を置いてランダムな値を生成するだけで遊んでいます。これは、私が現在立ち往生している場所の例です(jQueryのanimate function()を使用):

<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>

これは「正しく」見えません。オーディオ信号のように「感じる」データを生成できる機能はありますか? この問題に対する他のアプローチにも興味があります (おそらく、HTML5 オーディオをサポートするブラウザーでスペクトル アナライザー データをキャプチャし、古いブラウザーで「再生」する必要があるだけです)。

これは、私が目指している種類の外観の例です。

ここに画像の説明を入力

JavaScript でのベジエ曲線の実装を少し検索した後、生成されたシングルを混合して何かを生成し始めました。私の仕事は未完成ですが、これが他の誰かに何かアイデアを与える場合に備えて、ここにデモがあります。

4

4 に答える 4

8

スペクトルをリアルに見せる (仮想データであろうとなかろうと) ための鍵は、バンド バーのフォールバック メカニズムを持つことです。

帯域は、新しい値が現在の値よりも高い場合にのみ設定されます。そうでない場合、現在の値は値 (線形または対数) だけ減少します。フォールバックの速度も認識に影響します。

スペクトル アナライザーのデータは実際の波形ではなく、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/

スタイル付きバージョン

于 2013-06-05T06:37:56.770 に答える
3

私はもっ​​と近づいていると思います(しかし、私は多くのことを行ってきたので、自分の質問への回答としてそれを提供することが最善のアプローチであると考えました. )。これまでに実装した (複雑な) コード ( demo ) を次に示します。

HTML と CSS のクリーンアップされたバージョンを使用すると、JavaScript が次のようになります。

var amp = 0,
    flutter_range = 10,
    channels = $('.channel'),
    turnItUp = setInterval(function () {
        amp += 0.01;
    }, 50),
    flutter = setInterval(function () {
        var levels = bezier([[0.3], [0.95], [1], [0]]),
            channel;
        for(channel = 0; channel < channels.length; channel++) {
            $(channels[channel]).animate({
                height: 245-(Math.round(((Math.random() * (flutter_range*2))-flutter_range)+(levels(channel/channels.length)*amp)*245))+'px'
            }, 50);
        }
    }, 100),
    //from: https://gist.github.com/atomizer/1049745
    bezier = function (pts) {
        return function (t) {
            for (var a = pts; a.length > 1; a = b) // do..while loop in disguise
                for (var i = 0, b = [], j; i < a.length - 1; i++) // cycle over control points
                    for (b[i] = [], j = 0; j < a[i].length; j++) // cycle over dimensions
                        b[i][j] = a[i][j] * (1 - t) + a[i + 1][j] * t; // interpolation
            return a[0];
        }
    };

setTimeout(function () {
    window.clearInterval(turnItUp);
}, 5000);

その仕組みは、ベジエ カーブを作成しながら「アンプ」を 5 秒間上げてから、データにランダムな「フラッター」を適用して「オーディオ フィール」を与えることです。ベジエ関数は、この要点から来ています。

于 2013-05-28T17:31:59.790 に答える
2

アニメーションをリアルに見せる最善の方法は、実際のデータを使用し、バーの実際の値を計算することだと思います。実際のデータでアニメーションを行うと、バーがリアルに上下します。この動作は、処理を行わないと真似するのが難しい場合があります。

イコライザー バーが示すのは、さまざまな周波数範囲の振幅です。これらのバーは、FFT (高速フーリエ変換) と呼ばれる関数を使用して、実際のオーディオ ファイルから計算できます。

Javascript を含め、ほぼすべての言語に FFT の実装があります。アルゴリズムは次のように機能します。

  • 更新するフレーム レートを決定します。
  • オーディオ ファイルから 1/fps 相当のサンプルをメモリ バッファーにロードします (非圧縮、.mp3 の場合は最初に .wav に変換します)。
  • バッファーを FFT 関数に送信します。戻り値の配列を持つ別のバッファを取得します。
  • 表示するバーの数を決定し、関心のあるデータを含むサンプル数が多い FFT バッファーの部分を見つけます。多数の連続する値を平均化することにより、出力 FFT 配列を圧縮することもできます。
  • 配列 (または平均化されたグループ) の各値は、バーの高さを示します。
  • これにより、アニメーションの 1 フレームが得られます。オーディオの次の 1/fps を取得し、プロセス全体を繰り返して次のフレームを取得します。

FFT はかなり CPU を集中的に使用するため、十分なフレームのバーを計算し、計算した値をスクリプトで使用することができます。

開始するための例が必要な場合は、このデモをご覧ください: Fast Fourier Transforms with audiolib.js

このデモでは、合成波形を生成し、ブラウザで再生し (必要ありません)、Canvas オブジェクトにリアルタイムのイコライザーを描画します。このページの例は、何らかの理由で機能しないため、ソース コードの要旨をダウンロードし、コンピューターにインストールして機能させました。

于 2013-06-03T02:27:50.063 に答える