是否可以在iPhone上实时移相音频?
我有一个简单的应用程序设置,可以实时输出麦克风的音频。我要做的是处理这个音频,即做一个相移。
我是否正确,唯一的方法是采取我的样本空间,进行FFT,相移,然后反转fft?
我知道vDSP库,但对于一个简单的任务来说似乎是太多的开销。
更新:我有来自Elec Eng的DSP基础,是的,我确实想做相移。我不需要进行频移或过滤,它们是单独的过程,我稍后会实现。
答案 0 :(得分:3)
是的,这是一种方法。
此示例C代码显示:
#include <stdio.h>
#include <math.h>
#ifndef M_PI
#define M_PI 3.14159265358979324
#endif
typedef struct
{
double x, y;
} tComplex;
tComplex complexAdd(const tComplex* a, const tComplex* b)
{
tComplex c;
c.x = a->x + b->x;
c.y = a->y + b->y;
return c;
}
tComplex complexMul(const tComplex* a, const tComplex* b)
{
tComplex c;
c.x = a->x * b->x - a->y * b->y;
c.y = a->x * b->y + a->y * b->x;
return c;
}
void dft(tComplex out[], const tComplex in[], size_t n, int direction)
{
size_t k, i;
for (k = 0; k < n; k++)
{
tComplex r = { 0, 0 }, e;
for (i = 0; i < n; i++)
{
e.x = cos(-2 * direction * M_PI / n * ((double)k - n / 2) * ((double)i - n / 2));
e.y = sin(-2 * direction * M_PI / n * ((double)k - n / 2) * ((double)i - n / 2));
e = complexMul(&e, &in[i]);
r = complexAdd(&r, &e);
}
out[k] = r;
}
}
double maxAbs(const tComplex in[], size_t n)
{
double m = 0;
while (n--)
{
double a = hypot(in->x, in->y);
if (m < a) m = a;
in++;
}
return m;
}
#define SAMPLE_CNT 32
#define SAMPLE_SHIFT 3
int main(void)
{
tComplex signalIn[SAMPLE_CNT];
tComplex signalOut[SAMPLE_CNT];
tComplex tmp[SAMPLE_CNT];
int i;
// signalIn[] = square pulse
for (i = 0; i < SAMPLE_CNT; i++)
{
signalIn[i].x = ((i - SAMPLE_CNT / 2) >= 0) * ((i - SAMPLE_CNT / 2) < SAMPLE_CNT / 4);
signalIn[i].y = 0;
}
// tmp[] = DFT{signalIn[]}
dft(tmp, signalIn, SAMPLE_CNT, 1);
// tmp[] = DFT{signalIn[]} * exp(j * 2 * PI * f * TimeShift)
for (i = 0; i < SAMPLE_CNT; i++)
{
tComplex e;
e.x = cos(2 * M_PI * (i - SAMPLE_CNT / 2) * SAMPLE_SHIFT / SAMPLE_CNT);
e.y = -sin(2 * M_PI * (i - SAMPLE_CNT / 2) * SAMPLE_SHIFT / SAMPLE_CNT);
tmp[i] = complexMul(&tmp[i], &e);
}
// signalOut[] = IDFT{tmp[]}
dft(signalOut, tmp, SAMPLE_CNT, -1);
printf(" Re{In[]} . Im{In[]} |"
" |DFT{In[]}| |"
" Re{Out[]} . Im{Out[]}\n");
for (i = 0; i < SAMPLE_CNT; i++)
{
int j, s;
s = signalIn[i].x / maxAbs(signalIn, SAMPLE_CNT) * 8 + .5;
for (j = -8; j <= 8; j++) printf("%c", " *"[s == j]);
printf(".");
s = signalIn[i].y / maxAbs(signalIn, SAMPLE_CNT) * 8 + .5;
for (j = -8; j <= 8; j++) printf("%c", " *"[s == j]);
printf("|");
s = hypot(tmp[i].x, tmp[i].y) / maxAbs(tmp, SAMPLE_CNT) * 8;
for (j = -8; j <= 8; j++) printf("%c", " *"[s == j]);
printf("|");
s = signalOut[i].x / maxAbs(signalOut, SAMPLE_CNT) * 8 + .5;
for (j = -8; j <= 8; j++) printf("%c", " *"[s == j]);
printf(".");
s = signalOut[i].y / maxAbs(signalOut, SAMPLE_CNT) * 8 + .5;
for (j = -8; j <= 8; j++) printf("%c", " *"[s == j]);
printf("\n");
}
return 0;
}
输出:
Re{In[]} . Im{In[]} | |DFT{In[]}| | Re{Out[]} . Im{Out[]}
* . * | * | * . *
* . * | * | * . *
* . * | * | * . *
* . * | * | * . *
* . * | * | * . *
* . * | * | * . *
* . * | * | * . *
* . * | * | * . *
* . * | * | * . *
* . * | * | * . *
* . * | * | * . *
* . * | * | * . *
* . * | * | * . *
* . * | * | * . *
* . * | * | * . *
* . * | * | * . *
*. * | *| * . *
*. * | * | * . *
*. * | * | * . *
*. * | * | *. *
*. * | * | *. *
*. * | * | *. *
*. * | * | *. *
*. * | * | *. *
* . * | * | *. *
* . * | * | *. *
* . * | * | *. *
* . * | * | * . *
* . * | * | * . *
* . * | * | * . *
* . * | * | * . *
* . * | * | * . *
您可以看到输出是由SAMPLE_SHIFT
个样本(此处为3)移位的输入的副本。
您也可以将SAMPLE_SHIFT
更改为非整数值,按小数个样本进行移位。
SAMPLE_SHIFT
= 2.5的输出:
Re{In[]} . Im{In[]} | |DFT{In[]}| | Re{Out[]} . Im{Out[]}
* . * | * | * . *
* . * | * | * . *
* . * | * | * . *
* . * | * | * . *
* . * | * | * . *
* . * | * | * . *
* . * | * | * . *
* . * | * | * . *
* . * | * | * . *
* . * | * | * . *
* . * | * | * . *
* . * | * | * . *
* . * | * | * . *
* . * | * | * . *
* . * | * | * . *
* . * | * | * . *
*. * | *| * . *
*. * | * | * . *
*. * | * | * . *
*. * | * | *. *
*. * | * | * . *
*. * | * | * . *
*. * | * | * . *
*. * | * | * . *
* . * | * | * . *
* . * | * | *. *
* . * | * | * . *
* . * | * | * . *
* . * | * | * . *
* . * | * | * . *
* . * | * | * . *
* . * | * | * . *
答案 1 :(得分:0)
你想要做的事情应该对应于输出是带有内核的输入的折叠积分。它可以作为脉冲输入的输出。如果您能找到它,请使用适当的数字积分方法进行折叠积分。这相当于一个fft只需要完成一次,其余的应该连续完成以便连续输出。
答案 2 :(得分:0)
是否可以在iPhone上实时移相音频?
嗯,是的,但那可能不是你真正想做的事情。 (见TJD的评论)
我有一个简单的应用程序设置,可以实时输出麦克风的音频。我要做的是处理这个音频,即做一个相移。
处理音频不是进行相移的同义词。也许你想“过滤”?
我是否正确,唯一的方法是采取我的样本空间,进行FFT,相移,然后反转fft?
假设您要做的是过滤音频,那么不,我不建议使用FFT。您将遇到许多问题,例如窗口,重叠/添加和性能。 FFT不是设计滤波器的好方法。
我知道vDSP库,但对于一个简单的任务来说似乎是太多的开销。
我从未使用过vDSP,但从快速检查来看,它看起来不像是正确的过滤解决方案。正确的解决方案更有可能使用简单的双二阶函数。你可以在这里阅读它们:
http://en.wikipedia.org/wiki/Digital_biquad_filter
这里有一本很棒的“食谱”:
答案 3 :(得分:0)
应该可以在iOS设备上实时进行各种音频处理。有足够的处理能力。
也许您可以更详细地描述您想要做什么样的相移。严格来说,“唯一”的方法是使用FFT,但这可能是最佳方式,至少在性能和电池寿命方面是这样。
当你说vDSP似乎有太多的开销时,你指的是处理器性能还是工程工作?我同意,vDSP有一些不受欢迎的工程努力,主要是由于传统接口要求将实数据(例如,输入信号)重新排列成奇偶分裂。但是,其他方面,例如FFT数据的设置,是必要的;它们受到FFT性质的驱使。
vDSP例程的计算性能应该非常好。如果您遇到困难,无论是处理器性能还是工程工作,请report bugs(或功能请求)。
答案 4 :(得分:0)
我同意其他人的观点,即(实时正向)相移不需要DSP,因为它只是音频采样的时移。当然,实时后向相移需要比DSP更多的努力,因为它需要时间旅行。
另一方面,我需要一种简单快捷的方法来执行iphone麦克风音频样本的固定频移。实际上有几个频率偏移,例如1Hz增量或大约。有人知道在iPhone上执行该任务的快捷方式吗?