将线性音频频率分布转换为对数/感知分布?

时间:2015-08-31 21:10:21

标签: math audio logarithm beep

我正在为脚本创建一些音频提示,并继续遇到同样的问题:

人类感知是对数的。如果我想将一系列声音切成10个相等的部分,我就不能从最高音高中减去最低音高并除以10.这些步骤在感知上并不准确。

因此,当处理一个给出20-20000范围(kHz)输出的函数时,是否有一个基本的数学函数合理地近似将这些数字转换为它们的感知等价物 - 虽然仍然在20-20000范围内进行映射?

示例:

我正在处理一个" beep"将kHz作为范围的命令。

我从我自己的系统测试中知道,正在测试的系统上该命令的功能范围是38到9900Hz。

因此,如果我创建一个音频倒计时来完成100项,我会将9900-38 / 100划分为每项98.62Hz范围。如果我要创建一个音频倒计时,我只需创建一个从最大范围开始的哔哔声序列,每哔哔声减少98.62Hz。

但这听起来并不准确。大部分时间花在高声频率上。没有足够的时间花在低音频率上。

我确实设法为我的白噪声发生器修复了这个问题,但我无法对音频倒计时应用同样的修复方法。 (主要是因为在白噪声发生器中存在相当大的错误余地。)在那种情况下,我简单地用Hz除以10.但是我随机地这样做了。它给了我期望的效果,但没有任何一致的映射函数:

        if  %@RANDOM[1,10] gt 6 (set BEEP_FREQUENCY_TEMP=%@FLOOR[%@EVAL[BEEP_FREQUENCY_TEMP / 10]] 
        if  %@RANDOM[1,10] gt 9 (set BEEP_FREQUENCY_TEMP=%@FLOOR[%@EVAL[BEEP_FREQUENCY_TEMP / 10]] 
        if  %@RANDOM[1,10] gt 8 (set BEEP_FREQUENCY_TEMP=%@FLOOR[%@EVAL[BEEP_FREQUENCY_TEMP / 10]]

你能告诉我甚至不知道如何提出我的问题吗?

3 个答案:

答案 0 :(得分:1)

您需要使用对数间距:

// start - start frequency
// stop - stop frequency
// n - the point which you wish to compute (zero based)
// N - the number of points over which to divide the frequency
// range.
double logspace(double start, double stop, int n, int N)
{
    return start * pow(stop/start, n/(double)(N-1));
}

例如:

logspace(20, 200000, 0, 4) = 20
logspace(20, 200000, 1, 4) = 200
logspace(20, 200000, 2, 4) = 2000
logspace(20, 200000, 3, 4) = 20000

请注意,logspace(x,y,0,N)可能不完全相等xlogspace(x,y,N-1,N)可能不完全相等y。这是由于浮点精度和舍入误差造成的。

答案 1 :(得分:0)

你可能知道,从一个音调到另一个音调,音高会使其频率增加一倍。从那里再来一次八度音阶。所以你所拥有的是指数中基线的两个指数的线性增长(每个八度音程1或者每半音1/12):

f = 440Hz·2 x

现在将可能的x值范围划分为常规间隔,您应该完成。要将频率f转换为音高x,您需要计算对数,即

x = log 2 (f / 440Hz)= ln(f / 440Hz)/ ln(2)

答案 2 :(得分:0)

我最终查找了所有与音符匹配的频率列表,制作了一个文本文件,其中包含所有这些频率,并且只需按照我想要的间隔迭代它。例如,如果我想要一个表示10%上传进度的注释,则需要总行数,并通过该文件获取10%的行。这解决了使我的音频倒计时声音线性的问题,即使这样做所需的频率不是线性的。

查找表。

不优雅,但有效。