从Audio获取logarithmic byteFrequencyData

Seb*_*sen 7 javascript web-audio-api

我问了一个类似于此前的问题,但它没有解决我的问题并且解释得很差.这次我做了插图,希望能更好地解释.

我的音频播放器有一个简单的频谱分析仪.频率存储在每个都更新的数组中requestAnimationFrame,数组如下所示:

fbc_array = new Uint8Array(analyser.frequencyBinCount);
analyser.getByteFrequencyData(fbc_array);
Run Code Online (Sandbox Code Playgroud)

在这里阅读更多关于getByteFrequencyData的信息.

所以这个工作正常,但我希望频率在整个频谱中均匀分布.现在它显示线性频率:

在此输入图像描述

正如您所看到的,这里的主要频率范围是高音(高端),最主要的频率范围是低音范围(低端).我希望我的分析仪具有均匀分布的频率范围,如下所示:

在此输入图像描述

在这里,您可以看到分析仪上均匀分布的频率.这可能吗?

我用于生成分析器的代码如下所示:

// These variables are dynamically changed, ignore them.
var canbars = 737
var canmultiplier = 8
var canspace = 1

// The analyser
var canvas, ctx, source, context, analyser, fbc_array, bars, bar_x,
    bar_width, bar_height;

function audioAnalyserFrame() {
    'use strict';
    var i;
    canvas.width = $('analyser-').width();
    canvas.height = $('analyser-').height();
    ctx.imageSmoothingEnabled = false;
    fbc_array = new Uint8Array(analyser.frequencyBinCount);
    analyser.getByteFrequencyData(fbc_array);
    ctx.clearRect(0, 0, canvas.width, canvas.height); // Clear the canvas
    ctx.fillStyle = "white"; // Color of the bars
    bars = canbars;
    for (i = 0; i < bars; i += canmultiplier) {
        bar_x = i * canspace;
        bar_width = 2;
        bar_height = -3 - (fbc_array[i] / 2);
        ctx.fillRect(bar_x, canvas.height, bar_width, bar_height);
    }
    window.requestAnimationFrame(audioAnalyserFrame);
}

function audioAnalyserInitialize() {
    'use strict';
    var analyserElement = document.getElementById('analyzer');

    if (analyserElement !== null && audioViewIsCurrent() === true) {
        if (analyserInitialized === false) {
            context = new AudioContext();
            source = context.createMediaElementSource(audioSource);
        } else {
            analyser.disconnect();
        }
        analyser = context.createAnalyser();
        canvas = analyserElement;
        ctx = canvas.getContext('2d');
        source.connect(analyser);
        analyser.connect(context.destination);
        if (analyserInitialized === false) {
            audioAnalyserFrame();
        }
        analyserInitialized = true;
        analyser.smoothingTimeConstant = 0.7;
    }
}
Run Code Online (Sandbox Code Playgroud)

请注意,我canmultiplier在for循环中跳过8个条形(参见顶部)(如果我没有,分析器的另一半会在画布外部渲染,因为它太大了.)我不知道这是不是还有什么可能导致不一致的频率范围.

小智 5

如果我理解正确的话,我认为这对你有用,尽管远非完美。

您在 for 循环中所做的是对数组进行采样,每 8 个元素采样一次。我要做的是以对数方式进行采样。

一个例子:

//Given a range, transforms a value from linear scale to log scale.
var toLog = function(value, min, max){
    var exp = (value-min) / (max-min);
  return min * Math.pow(max/min, exp);
}

//This would be the frequency array in a linear scale
var arr = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20];

//In this case i'm using a range from 1 to 20, you would use the size of your array. I'm incrementing 'i' by one each time, but you could also change that
for (var i = 1; i < 20; i += 1) {
  //I'm starting at 1 because 0 and logarithms dont get along
  var logindex = toLog(i,1,19); //the index we want to sample

  //As the logindex will probably be decimal, we need to interpolate (in this case linear interpolation)
  var low = Math.floor(logindex);
  var high = Math.ceil(logindex);
  var lv = arr[low];
  var hv = arr[high];
  var w = (logindex-low)/(high-low);
  var v = lv + (hv-lv)*w; //the interpolated value of the original array in the logindex index.
    document.write(v + "<br/>");  //In your case you should draw the bar here or save it in an array for later.
}
Run Code Online (Sandbox Code Playgroud)

我希望我能很好地解释自己。这里你有一个工作演示,有一些边界错误,但它可以按照我认为你需要的方式工作。