Apple的讲话背后的数学说明这里的例子

时间:2012-12-18 17:58:45

标签: objective-c ios audio core-audio avaudioplayer

我对Apple正在使用的数学speak here example有疑问。

一点背景:我知道AVAudioRecorder和AVAudioPlayer返回的平均功率和峰值功率以dB为单位。我也理解为什么RMS功率以dB为单位,需要使用pow(10, (0.5 * avgPower))将其转换为放大器。

我的问题是:

Apple使用此公式创建它的“Meter Table”

MeterTable::MeterTable(float inMinDecibels, size_t inTableSize, float inRoot)
    : mMinDecibels(inMinDecibels),
    mDecibelResolution(mMinDecibels / (inTableSize - 1)), 
    mScaleFactor(1. / mDecibelResolution)
{
    if (inMinDecibels >= 0.)
    {
        printf("MeterTable inMinDecibels must be negative");
        return;
    }

    mTable = (float*)malloc(inTableSize*sizeof(float));

    double minAmp = DbToAmp(inMinDecibels);
    double ampRange = 1. - minAmp;
    double invAmpRange = 1. / ampRange;

    double rroot = 1. / inRoot;
    for (size_t i = 0; i < inTableSize; ++i) {
        double decibels = i * mDecibelResolution;
        double amp = DbToAmp(decibels);
        double adjAmp = (amp - minAmp) * invAmpRange;
        mTable[i] = pow(adjAmp, rroot);
    }
}

所有计算是什么 - 或者更确切地说,这些步骤的作用是什么?我认为mDecibelResolutionmScaleFactor用于绘制超过400个值的80dB范围(除非我弄错了)。但是,inRootampRangeinvAmpRangeadjAmp的重要性是什么?另外,为什么仪表中的第i个条目为“mTable[i] = pow(adjAmp, rroot);”?

非常感谢任何帮助! :)

提前致谢并欢呼!

2 个答案:

答案 0 :(得分:8)

自从我问过这个问题已经过去了一个月,感谢Geebs,感谢您的回复! :)

所以,这与我一直在研究的项目有关,基于此的功能是在提出问题后约2天实施的。显然,我已经发布了一个结束回复(对不起)。我也在1月7日发表评论,但是回过头来看,似乎我对var名称感到困惑。 &GT; _&LT ;.以为我会给这个问题提供一个完整的逐行答案(带图片)。 :)

所以,这里是:

//mDecibelResolution is the "weight" factor of each of the values in the meterTable.
//Here, the table is of size 400, and we're looking at values 0 to 399.
//Thus, the "weight" factor of each value is minValue / 399.


MeterTable::MeterTable(float inMinDecibels, size_t inTableSize, float inRoot)
    : mMinDecibels(inMinDecibels),
    mDecibelResolution(mMinDecibels / (inTableSize - 1)), 
    mScaleFactor(1. / mDecibelResolution)
{
    if (inMinDecibels >= 0.)
    {
        printf("MeterTable inMinDecibels must be negative");
        return;
    }

    //Allocate a table to store the 400 values
    mTable = (float*)malloc(inTableSize*sizeof(float));

    //Remember, "dB" is a logarithmic scale.
    //If we have a range of -160dB to 0dB, -80dB is NOT 50% power!!!
    //We need to convert it to a linear scale. Thus, we do pow(10, (0.05 * dbValue)), as stated in my question.

    double minAmp = DbToAmp(inMinDecibels);

    //For the next couple of steps, you need to know linear interpolation.
    //Again, remember that all calculations are on a LINEAR scale.
    //Attached is an image of the basic linear interpolation formula, and some simple equation solving.

Linear Interpolation Equation

    //As per the image, and the following line, (y1 - y0) is the ampRange - 
    //where y1 = maxAmp and y0 = minAmp.
    //In this case, maxAmp = 1amp, as our maxDB is 0dB - FYI: 0dB = 1amp.
    //Thus, ampRange = (maxAmp - minAmp) = 1. - minAmp
    double ampRange = 1. - minAmp;

    //As you can see, invAmpRange is the extreme right hand side fraction on our image's "Step 3"
    double invAmpRange = 1. / ampRange;

    //Now, if we were looking for different values of x0, x1, y0 or y1, simply substitute it in that equation and you're good to go. :)
    //The only reason we were able to get rid of x0 was because our minInterpolatedValue was 0.

    //I'll come to this later.
    double rroot = 1. / inRoot;

    for (size_t i = 0; i < inTableSize; ++i) {
        //Thus, for each entry in the table, multiply that entry with it's "weight" factor.
        double decibels = i * mDecibelResolution;

        //Convert the "weighted" value to amplitude using pow(10, (0.05 * decibelValue));
        double amp = DbToAmp(decibels);

        //This is linear interpolation - based on our image, this is the same as "Step 3" of the image.
        double adjAmp = (amp - minAmp) * invAmpRange;

        //This is where inRoot and rroot come into picture.
        //Linear interpolation gives you a "straight line" between 2 end-points.
       //rroot =  0.5
       //If I raise a variable, say myValue by 0.5, it is essentially taking the square root of myValue.
       //So, instead of getting a "straight line" response, by storing the square root of the value,
       //we get a curved response that is similar to the one drawn in the image (note: not to scale).
        mTable[i] = pow(adjAmp, rroot);
    }
}

响应曲线图像:如您所见,“线性曲线”并非完全是曲线。 &GT; _&LT; Square root response image

希望这能以某种方式帮助社区。 :)

答案 1 :(得分:2)

没有专家,但基于物理和数学:

假设最大振幅为1且最小值为0.0001 [对应于-80db,这是在苹果示例中设置的min db值:AQLevelMeter.h中的#define kMinDBvalue -80.0]

minAmp是此示例的最小幅度= 0.0001

现在,所有正在进行的工作是以分贝分辨率的倍数为单位的振幅与最小振幅进行调整:
调整幅度=(amp-minamp)/(1-minamp)
这使得调整幅度的范围= 0到1而不是0.0001到1(如果需要的话)。

inRoot在这里设置为2。 rroot = 1/2 - 提高功率1/2是平方根。来自apple的文件:
// inRoot - 它控制响应的曲率。 2.0是平方根,3.0是立方根。但是inRoot不必是整数值,它可以是1.8或2.5等。
基本上为您提供0到1之间的响应,其曲率根据您为inRoot设置的值而变化。