我应该从 getFft 看到什么样的输出?
好吧,我正在努力创建一个 Android 音频可视化应用程序。问题是,我从 getFft() 方法中得到的结果与谷歌所说的它应该产生的结果不一致。我一直追溯到 C++ 源代码,但我对 C++ 或 FFT 不够熟悉,无法真正理解正在发生的事情。
我将尝试包含此处所需的所有内容:
(Java) Visualizer.getFft(byte[] fft)
/**
* Returns a frequency capture of currently playing audio content. The capture is a 8-bit
* magnitude FFT. Note that the size of the FFT is half of the specified capture size but both
* sides of the spectrum are returned yielding in a number of bytes equal to the capture size.
* {@see #getCaptureSize()}.
* <p>This method must be called when the Visualizer is enabled.
* @param fft array of bytes where the FFT should be returned
* @return {@link #SUCCESS} in case of success,
* {@link #ERROR_NO_MEMORY}, {@link #ERROR_INVALID_OPERATION} or {@link #ERROR_DEAD_OBJECT}
* in case of failure.
* @throws IllegalStateException
*/
public int getFft(byte[] fft)
throws IllegalStateException {
synchronized (mStateLock) {
if (mState != STATE_ENABLED) {
throw(new IllegalStateException("getFft() called in wrong state: "+mState));
}
return native_getFft(fft);
}
}
(C++) Visualizer.getFft(uint8_t *fft)
status_t Visualizer::getFft(uint8_t *fft)
{
if (fft == NULL) {
return BAD_VALUE;
}
if (mCaptureSize == 0) {
return NO_INIT;
}
status_t status = NO_ERROR;
if (mEnabled) {
uint8_t buf[mCaptureSize];
status = getWaveForm(buf);
if (status == NO_ERROR) {
status = doFft(fft, buf);
}
} else {
memset(fft, 0, mCaptureSize);
}
return status;
}
(C++) Visualizer.doFft(uint8_t *fft, uint8_t *waveform)< /a>
status_t Visualizer::doFft(uint8_t *fft, uint8_t *waveform)
{
int32_t workspace[mCaptureSize >> 1];
int32_t nonzero = 0;
for (uint32_t i = 0; i < mCaptureSize; i += 2) {
workspace[i >> 1] = (waveform[i] ^ 0x80) << 23;
workspace[i >> 1] |= (waveform[i + 1] ^ 0x80) << 7;
nonzero |= workspace[i >> 1];
}
if (nonzero) {
fixed_fft_real(mCaptureSize >> 1, workspace);
}
for (uint32_t i = 0; i < mCaptureSize; i += 2) {
fft[i] = workspace[i >> 1] >> 23;
fft[i + 1] = workspace[i >> 1] >> 7;
}
return NO_ERROR;
}
(C++)fixedfft。 fixed_fft_real(int n, int32_t *v)
void fixed_fft_real(int n, int32_t *v)
{
int scale = LOG_FFT_SIZE, m = n >> 1, i;
fixed_fft(n, v);
for (i = 1; i <= n; i <<= 1, --scale);
v[0] = mult(~v[0], 0x80008000);
v[m] = half(v[m]);
for (i = 1; i < n >> 1; ++i) {
int32_t x = half(v[i]);
int32_t z = half(v[n - i]);
int32_t y = z - (x ^ 0xFFFF);
x = half(x + (z ^ 0xFFFF));
y = mult(y, twiddle[i << scale]);
v[i] = x - y;
v[n - i] = (x + y) ^ 0xFFFF;
}
}
(C++)fixedfft.fixed_fft(int n, int32_t *v)
void fixed_fft(int n, int32_t *v)
{
int scale = LOG_FFT_SIZE, i, p, r;
for (r = 0, i = 1; i < n; ++i) {
for (p = n; !(p & r); p >>= 1, r ^= p);
if (i < r) {
int32_t t = v[i];
v[i] = v[r];
v[r] = t;
}
}
for (p = 1; p < n; p <<= 1) {
--scale;
for (i = 0; i < n; i += p << 1) {
int32_t x = half(v[i]);
int32_t y = half(v[i + p]);
v[i] = x + y;
v[i + p] = x - y;
}
for (r = 1; r < p; ++r) {
int32_t w = MAX_FFT_SIZE / 4 - (r << scale);
i = w >> 31;
w = twiddle[(w ^ i) - i] ^ (i << 16);
for (i = r; i < n; i += p << 1) {
int32_t x = half(v[i]);
int32_t y = mult(w, v[i + p]);
v[i] = x - y;
v[i + p] = x + y;
}
}
}
}
如果你完成了这一切,那你就太棒了!所以我的问题是,当我调用 java 方法 getFft() 时,我最终会得到负值,如果返回的数组旨在表示大小,则该负值不应该存在。所以我的问题是,我需要做什么才能使数组代表大小?
编辑:看来我的数据实际上可能是傅立叶系数。我在网上浏览了一下,发现了这个。小程序“Start Function FFT”显示系数的图形表示,它是我绘制 getFft() 中的数据时所发生情况的真实图像。新问题:这是我的数据吗?如果是这样,我如何从系数进行频谱分析?
Alright, so I am working on creating an Android audio visualization app. The problem is, what I get form the method getFft() doesn't jive with what google says it should produce. I traced the source code all the way back to C++, but I am not familiar enough with C++ or FFT to actually understand what is happening.
I will try and include everything needed here:
(Java) Visualizer.getFft(byte[] fft)
/**
* Returns a frequency capture of currently playing audio content. The capture is a 8-bit
* magnitude FFT. Note that the size of the FFT is half of the specified capture size but both
* sides of the spectrum are returned yielding in a number of bytes equal to the capture size.
* {@see #getCaptureSize()}.
* <p>This method must be called when the Visualizer is enabled.
* @param fft array of bytes where the FFT should be returned
* @return {@link #SUCCESS} in case of success,
* {@link #ERROR_NO_MEMORY}, {@link #ERROR_INVALID_OPERATION} or {@link #ERROR_DEAD_OBJECT}
* in case of failure.
* @throws IllegalStateException
*/
public int getFft(byte[] fft)
throws IllegalStateException {
synchronized (mStateLock) {
if (mState != STATE_ENABLED) {
throw(new IllegalStateException("getFft() called in wrong state: "+mState));
}
return native_getFft(fft);
}
}
(C++) Visualizer.getFft(uint8_t *fft)
status_t Visualizer::getFft(uint8_t *fft)
{
if (fft == NULL) {
return BAD_VALUE;
}
if (mCaptureSize == 0) {
return NO_INIT;
}
status_t status = NO_ERROR;
if (mEnabled) {
uint8_t buf[mCaptureSize];
status = getWaveForm(buf);
if (status == NO_ERROR) {
status = doFft(fft, buf);
}
} else {
memset(fft, 0, mCaptureSize);
}
return status;
}
(C++) Visualizer.doFft(uint8_t *fft, uint8_t *waveform)
status_t Visualizer::doFft(uint8_t *fft, uint8_t *waveform)
{
int32_t workspace[mCaptureSize >> 1];
int32_t nonzero = 0;
for (uint32_t i = 0; i < mCaptureSize; i += 2) {
workspace[i >> 1] = (waveform[i] ^ 0x80) << 23;
workspace[i >> 1] |= (waveform[i + 1] ^ 0x80) << 7;
nonzero |= workspace[i >> 1];
}
if (nonzero) {
fixed_fft_real(mCaptureSize >> 1, workspace);
}
for (uint32_t i = 0; i < mCaptureSize; i += 2) {
fft[i] = workspace[i >> 1] >> 23;
fft[i + 1] = workspace[i >> 1] >> 7;
}
return NO_ERROR;
}
(C++) fixedfft.fixed_fft_real(int n, int32_t *v)
void fixed_fft_real(int n, int32_t *v)
{
int scale = LOG_FFT_SIZE, m = n >> 1, i;
fixed_fft(n, v);
for (i = 1; i <= n; i <<= 1, --scale);
v[0] = mult(~v[0], 0x80008000);
v[m] = half(v[m]);
for (i = 1; i < n >> 1; ++i) {
int32_t x = half(v[i]);
int32_t z = half(v[n - i]);
int32_t y = z - (x ^ 0xFFFF);
x = half(x + (z ^ 0xFFFF));
y = mult(y, twiddle[i << scale]);
v[i] = x - y;
v[n - i] = (x + y) ^ 0xFFFF;
}
}
(C++) fixedfft.fixed_fft(int n, int32_t *v)
void fixed_fft(int n, int32_t *v)
{
int scale = LOG_FFT_SIZE, i, p, r;
for (r = 0, i = 1; i < n; ++i) {
for (p = n; !(p & r); p >>= 1, r ^= p);
if (i < r) {
int32_t t = v[i];
v[i] = v[r];
v[r] = t;
}
}
for (p = 1; p < n; p <<= 1) {
--scale;
for (i = 0; i < n; i += p << 1) {
int32_t x = half(v[i]);
int32_t y = half(v[i + p]);
v[i] = x + y;
v[i + p] = x - y;
}
for (r = 1; r < p; ++r) {
int32_t w = MAX_FFT_SIZE / 4 - (r << scale);
i = w >> 31;
w = twiddle[(w ^ i) - i] ^ (i << 16);
for (i = r; i < n; i += p << 1) {
int32_t x = half(v[i]);
int32_t y = mult(w, v[i + p]);
v[i] = x - y;
v[i + p] = x + y;
}
}
}
}
If you made it through all that, you are awesome! So my issue, is when I call the java method getFft() I end up with negative values, which shouldn't exist if the returned array is meant to represent magnitude. So my question is, what do I need to do to make the array represent magnitude?
EDIT: It appears my data may actually be the Fourier coefficients. I was poking around the web and found this. The applet "Start Function FFT" displays a graphed representation of coefficients and it is a spitting image of what happens when I graph the data from getFft(). So new question: Is this what my data is? and if so, how do I go from the coefficients to a spectral analysis of it?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
为什么您看到负值的一个可能的解释是:
byte
是Java中的有符号数据类型。所有大于或等于1000 0000
2 的值都被解释为负整数。如果我们知道所有值都应该在
[0..255]
范围内,那么我们就可以将这些值映射到更大的类型并过滤高位:One possible explanation why you see negative values:
byte
is a signed data type in Java. All values, that are greater or equal1000 0000
2 are interpreted as negative integers.If we know that all values should are expected to be in the range
[0..255]
, then we have map the values to a larger type and filter the upper bits:“捕获是 8 位幅度 FFT”可能意味着返回值具有 8 位幅度,而不是它们本身就是幅度。
根据 杰森
Android 2.3 Visualizer - 理解 getFft() 时遇到问题
"The capture is a 8-bit magnitude FFT" probably means that the return values have an 8-bit magnitude, not that they are magnitudes themselves.
According to Jason
Android 2.3 Visualizer - Trouble understanding getFft()
FFT 不仅产生幅度,还产生幅度。它也产生相位(每个样本的输出是一个复数)。如果您想要幅度,那么您需要为每个输出样本显式计算它,如
re*re + im*im
,其中re
和im
> 分别是每个复数的实部和虚部。不幸的是,我在代码中看不到任何处理复数的地方,因此也许需要进行一些重写。
更新
如果我必须猜测(浏览代码后),我会说实数分量位于偶数索引,奇数分量位于奇数索引。因此,要获得幅度,您需要执行以下操作:
An FFT doesn't just produce magnitude; it produces phase as well (the output for each sample is a complex number). If you want magnitude, then you need to explicitly calculate it for each output sample, as
re*re + im*im
, wherere
andim
are the real and imaginary components of each complex number, respectively.Unfortunately, I can't see anywhere in your code where you're working with complex numbers, so perhaps some rewrite is required.
UPDATE
If I had to guess (after glancing at the code), I'd say that real components were at even indices, and odd components were at odd indices. So to get magnitudes, you'd need to do something like: