- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
我编写了一个程序,它以用户指定的频率生成正弦波,并在 96kHz 音频 channel 上播放它。为了节省几个 CPU 周期,我采用了将一小段音频预渲染到缓冲区中的老技巧,然后循环播放缓冲区,这样我就可以避免每秒调用 sin() 函数 96000 次程序的持续时间,只做简单的内存复制。
我的问题是有效地确定这个预渲染缓冲区的最小可用大小。对于某些频率,这很容易——例如,8kHz 正弦波可以通过生成 12 样本缓冲区并循环播放来完美表示,因为 (8000*12 == 96000)。然而,对于其他频率,正弦波的单个周期需要非整数数量的样本来表示,因此循环单个周期的样本值会导致 Not Acceptable 毛刺。
然而,对于其中一些频率,可以通过预渲染多个正弦波周期并循环播放来解决这个问题——如果我能计算出需要多少个周期,那么缓冲区中存在的循环将是完整的,同时还保证缓冲区中的样本数是完整的。例如,12.8kHz 的正弦波频率转换为 7.5 个样本的单周期缓冲区大小,这不会干净地循环,但如果我将正弦波的两个连续周期渲染到 15 个样本缓冲区中,那么我可以干净利落地循环结果。
我目前解决这个问题的方法是蛮力:我尝试了所有可能的循环计数,看看是否有任何一个产生了一个缓冲区大小,其中包含整数个样本。我认为这种方法并不令人满意,原因如下:
1) 效率很低。例如,下面显示的程序(打印 0Hz 到 48kHz 之间 480,000 个可能频率值的缓冲区大小结果)在我的 2.7GHz 机器上需要 35 分钟才能完成。我认为必须有一种更快的方法来做到这一点。
2) 由于浮点错误,我怀疑结果不是 100% 准确。
3) 如果找不到小于 10 秒长的可接受缓冲区大小,算法将放弃。 (我可以提高限制,但这当然会使算法变得更慢)。
那么,有什么方法可以分析地计算最小可用缓冲区大小,最好是在 O(1) 时间内?看起来应该很容易,但我一直无法弄清楚我应该使用什么样的数学。
提前感谢您的任何建议!
#include <stdio.h>
#include <math.h>
static const long long SAMPLES_PER_SECOND = 96000;
static const long long MAX_ALLOWED_BUFFER_SIZE_SAMPLES = (SAMPLES_PER_SECOND * 10);
// Returns the length of the pre-render buffer needed to properly
// loop a sine wave at the given frequence, or -1 on failure.
static int GetNumCyclesNeededForPreRenderedBuffer(float freqHz)
{
double oneCycleLengthSamples = SAMPLES_PER_SECOND/freqHz;
for (int count=1; (count*oneCycleLengthSamples) < MAX_ALLOWED_BUFFER_SIZE_SAMPLES; count++)
{
double remainder = fmod(oneCycleLengthSamples*count, 1.0);
if (remainder > 0.5) remainder = 1.0-remainder;
if (remainder <= 0.0) return count;
}
return -1;
}
int main(int, char **)
{
for (int i=0; i<48000*10; i++)
{
double freqHz = ((double)i)/10.0f;
int numCyclesNeeded = GetNumCyclesNeededForPreRenderedBuffer(freqHz);
if (numCyclesNeeded >= 0)
{
double oneCycleLengthSamples = SAMPLES_PER_SECOND/freqHz;
printf("For %.1fHz, use a pre-render-buffer size of %f samples (%i cycles, %f samples/cycle)\n", freqHz, (numCyclesNeeded*oneCycleLengthSamples), numCyclesNeeded, oneCycleLengthSamples);
}
else printf("For %.1fHz, there was no suitable pre-render-buffer size under the allowed limit!\n", freqHz);
}
return 0;
}
最佳答案
number_of_cycles/size_of_buffer = frequency/samples_per_second
这意味着如果您可以简化 frequency/samples_per_second 分数,则可以找到缓冲区的大小和缓冲区中的周期数。如果frequency和samples_per_second是整数,可以通过求最大公约数化简分数,否则可以用连分数的方法。
例子:
假设你的频率是 1234.5,你的 samples_per_second 是 96000。我们可以通过乘以 10 将它们变成两个整数,所以我们得到比率:
频率/samples_per_second = 12345/960000
最大公约数是15,所以可以约化为823/64000。
因此,您需要在 64000 个样本缓冲区中进行 823 个周期才能准确再现频率。
关于c++ - 如何有效地确定用于循环的预渲染正弦波音频缓冲区的最小必要大小?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11372183/
我写的函数有问题。想法是使用 taylor 展开而不是 js 数学对象来计算 sin 和 cosin 值(在 radians 上运行) .这些是方程式: sin(x) = (x^1)/1! - (x^
我不知道这是编程还是数学问题,但我整理了一些FFT的简短示例。我加载了440hz的波并在顶部添加了一些正弦波,但是由于某种原因,频谱中存在一个我不理解的“波”。 据我了解,频谱应该具有相同的| Y(f
这个问题在这里已经有了答案: Java Math.cos(Math.toRadians()) returns weird values (4 个答案) 关闭 10 年前。 我正在编写一个程序,我必须
我想在 ios4 中实现一个正弦和余弦计算器: if([operation isEqual:@"sin"]){ operand = (operand*M_PI/180.0); oper
我使用 256 个元素为 VHDL 制作了一个正弦 LUT。 我使用 MIDI 输入,因此值范围为 8.17Hz(注 #0)到 12543.85z(注 #127)。 我有另一个 LUT 计算必须发送到
我想在ios4中实现一个正弦和余弦计算器: if([operation isEqual:@"sin"]){ operand = (operand*M_PI/180.0); operan
我是一名优秀的程序员,十分优秀!