我在iOS中制作粒状合成器,基本上循环非常短的微量样本,以创建新的不可能的声音。为此,我在Core Audio中设置了录制和播放功能,但播放和循环播放的内容是来自谷物缓冲区的短样本。
我的问题是,当我从记录中的任意点取样时,循环样本的起点和终点不一定是过零点。因此,每次样品再次开始时,这可能导致点击,这通常在粒状合成中。我试图通过使用hann函数窗口化示例来解决这个问题,但是当我测试它时,结果是一个扭曲的混乱。请注意,为了便于测试,我的谷物缓冲液长22050个样品(1/2秒)。
// Window over entirety of the grain
for (int i = 0; i < 22050; i++)
{
// Hann window function, this is used as it zeros at beggining and end of window
double window = 0.5 * (1.0 - cos((2.0 * M_PI * i) / (22050 - 1)));
// Applying window
windowedGrain[i] = grainBufferNew[i] * window;
}
我出错的任何想法? windowedGrain缓冲区是否包含比grain缓冲区更多的样本?我写过hann函数错了吗?或者我没有正确应用窗口?任何可以给出的建议将不胜感激。
干杯
更新:自从进一步测试了问题以来,设置window = 1会产生无失真但无窗口的声音。我也使用了一个简单的三角窗函数,但这也是扭曲的,见下文
SInt16 sampleSizeGrainBuffer = sizeof(grainBufferNew)/sizeof(SInt16);
double window = 0.0;
double increment = 1.0/(sampleSizeGrainBuffer/2);
for (int i = 0; i < sampleSizeGrainBuffer; i++)
{
// Simple triangular window function
if (i<(sampleSizeGrainBuffer/2)) window += increment;
else window -= increment;
// Applying window
windowedGrain[i] = grainBufferNew[i] * window;
}
更新:错误似乎是由于最终的乘法,因为grainBufferNew是一个SInt16,窗口是一个双倍。这两者需要在数学上相等才能使其正常工作。由于窗口函数不能是SInt,因此必须首先将缓冲区数据设为double。然后在这个总和之后它必须转换回SInt 16。
更新:我尝试将grainBuffer转换为double,但结果仍然失真,尽管结果看起来很好。
// Applying window
windowedGrain[i] = (SInt16)(((double)grainBufferNew[i]) * window);
我还尝试将grainBuffer转换为double
// Applying window
windowedGrain[i] = ((double)grainBufferNew[i]) * window;
我尝试将窗口转换为SInt16,但结果是静音,因为窗口函数始终等于零。
// Applying window
windowedGrain[i] = grainBufferNew[i] * ((SInt16)window);
然后我尝试使用
来区分两个整数的大小windowedGrain[i] = grainBufferNew[i] * (window * sizeof(SInt16));
结果似乎结果似乎在终端窗口但输出失真