ram*_*age 5 android fft spectrum android-sdk-2.3
我有一些关于 FFT 的问题(实际上我相信这更多是关于 Visualizer.getFFT() 的 Android FFT 输出)。
我为 Android 创建了一个带有自己的库功能的音乐播放器,其中包括很多东西(如流派、动态播放列表和可视化)。目前,在渲染当前音频流的频谱时,我创建的可视化遇到了一些问题。
我已经阅读了以下问题(和答案)来了解 Android 的 FFT:
Android 2.3 Visualizer - 无法理解 getFft()
现在我的问题是:我从 getFFTs 系数获得的频谱似乎有些“奇怪”。我注意到,在播放歌曲时,我渲染的频谱似乎显示出很多“噪音”,因此我尝试使用一些测试声音。其中之一是简单的 8khz 声音,它应该只在图表中产生一个峰值。不幸的是,结果如下所示:
http://img4.imageshack.us/img4/4181/spectrum8khz.png
底部出现的噪声在图表的整个宽度上闪烁。高条保持在原位,仅在幅度上轻微闪烁。
当我使用从 1kHz 缓慢移动到 20kHz 的测试声音时,它看起来如下(大约 2-3kHz):
http://img846.imageshack.us/img846/7373/spectrum3khz1khz20khz.png
峰从左向右移动,每个峰的移动速度都快一点,因此随着时间的推移,峰之间的距离会逐渐增大。不可见的是,一旦峰值离开右侧屏幕(但幅度较小),它们就会返回并从右向左移动。此外,所有峰都在略大于屏幕 0.5 的位置处连接到一个大峰。
这是我用来检索数据的代码:
for (int i = 1; i < n / 2; i++) {
byte rfk = mRawSpecData[2*i];
byte ifk = mRawSpecData[2*i+1];
float magnitude = (float)Math.sqrt(rfk * rfk + ifk * ifk);
mFormattedSpecData[i-1] = magnitude / 128f;
}
Run Code Online (Sandbox Code Playgroud)
在上面的代码中,我的 mRawSpecData 是 Visualisers getFFT() 函数的结果。捕获的数据的长度是1024。当前斜率从1开始,因为mRawSpecData[0]包含DC并且mRawSpecData[1]包含n/2。
为了解决我的问题,我还尝试摆弄频率仓的直流和相位。我想也许我必须对幅度进行一些计算才能“清理”图表。但我没有成功(也许是因为我根本不明白直流/相位是怎么回事!)。
我花了两周的时间在晚上搜索谷歌并尝试不同的计算,但没有任何真正的帮助。
那么到底是怎么回事呢?我是否做错了什么或遗漏了什么?之后另一个困扰我的问题是如何正确缩放幅度。我的目标是获得 0f 和 1f 之间的值。
多谢
横冲直撞
PS:屏幕截图是通过 eclipse 从运行 Android 2.3 的手机上获取的。
PPS:我还用其他各种播放器(例如 winamp)检查了声音,在那里我看到了频谱的正确行为。
通过使用以下计算,我得到了很好的结果,以获得像这样的图像的可视化工具。我使用近 19 个图像来显示这样的内容。这些图像通过 getFFT() 方法输入进行响应。并且一定要启用均衡器和可视化器,否则它会给出高值,并且 fft 值会响应设备音量。实际上我无法由于我的英语,所以对代码进行解释。所以我在这里粘贴了代码。
展示台视图:
public class VisualizerView extends View {
private byte[] mBytes;
private float[] mPoints;
Paint mForePaint = new Paint();
// private int width;// height;
private Paint mPaint;
Bitmap mBmpArray[];
int wTilesize;
int hTilesize;
int no_of_colomuns;
private Bitmap peakBitmap;
private float changeFromTop, changeFromLeft;
private int images_drawn_starting_point ;
int magnitudePoints[];
int max[] = new int[34];
int temp[]=new int[32];
private final int[][] images = {
{ R.drawable.blue_fade_1, R.drawable.blue_fade_2,
R.drawable.blue_fade_3, R.drawable.blue_fade_4,
R.drawable.blue_fade_5, R.drawable.blue_fade_6,
R.drawable.blue_fade_7, R.drawable.blue_fade_8,
R.drawable.blue_fade_9, R.drawable.blue_fade_10,
R.drawable.blue_fade_11, R.drawable.blue_fade_12,
R.drawable.blue_fade_13, R.drawable.blue_fade_14,
R.drawable.blue_fade_15, R.drawable.blue_fade_16,
R.drawable.blue_fade_17, R.drawable.blue_fade_18,
R.drawable.blue_fade_19 }};
private final int IMAGES_LENTH = 19;
public VisualizerView(Context context) {
super(context);
mBmpArray = new Bitmap[20];
init();
}
public VisualizerView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public VisualizerView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
images_drawn_starting_point = h;
int temp;
wTilesize = w / 34;
// hTilesize = h / 30;
temp = h - ((IMAGES_LENTH - 1) );
hTilesize = temp / (IMAGES_LENTH );
no_of_colomuns = ( w / (wTilesize));
magnitudePoints = new int[no_of_colomuns];
changeFromLeft = wTilesize + 3f;//For spacing left
changeFromTop = hTilesize + 2.5f;//For spacing Right
}
public void init() {
mPaint = new Paint();
mPaint.setColor(Color.BLACK);
mPaint.setStrokeWidth(5f);
}
@Override
public void draw(Canvas canvas) {
super.draw(canvas);
int h = canvas.getHeight();
int w = canvas.getWidth();
canvas.drawRect(new Rect(0, 0, w, h), mPaint);
if (mBytes == null) {
return;
}
if (mPoints == null || mPoints.length < mBytes.length * 4) {
mPoints = new float[mBytes.length * 4];
}
double magnitude;
//VisualizerActivity.THEME_COLOR=0
for (int j = 0; j < IMAGES_LENTH; j++)
loadTile(j,getResources().getDrawable(images[VisualizerActivity.THEME_COLOR][j]));
for (int i = 0; i < no_of_colomuns; i++) {
byte rfk = mBytes[2 * i];
byte ifk = mBytes[2 * i + 1];
magnitude = ((rfk * rfk + ifk * ifk));
int dbValue = (int) (10 * Math.log10(magnitude));
magnitude = Math.round(dbValue * 8);
try {
magnitudePoints[i] = (int) magnitude;
} catch (Exception e) {
e.printStackTrace();
}
}
int left;
int top;
int index;
try {
index = 0;
left = 0;
int m = 1;
if (VisualizerActivity.THEME_STYLE == 0)
{
// common
for (int i = 0; i < no_of_colomuns; i++) {
top = images_drawn_starting_point;
index = 18;
for (int j = 0; j < IMAGES_LENTH; j++) {
if (j > magnitudePoints[m] / IMAGES_LENTH)
{
canvas.drawBitmap(mBmpArray[0], left, top, mPaint);
index++;
}
else
{
canvas.drawBitmap(mBmpArray[index--], left, top,
mPaint);
}
top -= changeFromTop;// hTilesize+1.5;
}
m++;
left += changeFromLeft;// wTilesize+2.5;
}
}
} catch (Exception e)
{
e.getMessage();
}
}
public void loadTile(int key, Drawable tile) {
try {
Bitmap bitmap = Bitmap.createBitmap(wTilesize, hTilesize,
Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
tile.setBounds(0, 0, wTilesize, hTilesize);
tile.draw(canvas);
mBmpArray[key] = bitmap;
} catch (Exception e) {
e.printStackTrace();
}
}
public void updateVisualizerWithFft(byte[] bytes) {
if (AudioPlayer.player != null) {
if (AudioPlayer.player.isPlaying()) {
mBytes = bytes;
}
}
invalidate();
}
}
Run Code Online (Sandbox Code Playgroud)
在 VisualizerActivity.java 中:
AudioPlayer.mVisualizer.setCaptureSize(Visualizer
.getCaptureSizeRange()[1]);
AudioPlayer.mVisualizer.setDataCaptureListener(
new Visualizer.OnDataCaptureListener() {
public void onWaveFormDataCapture(
Visualizer visualizer, byte[] bytes,
int samplingRate) {
// mVisualizerView.updateVisualizer(bytes);
}
public void onFftDataCapture(Visualizer visualizer,
byte[] bytes, int samplingRate) {
mVisualizerView.updateVisualizerWithFft(bytes);
}
}, Visualizer.getMaxCaptureRate() / 2, false, true);
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
6615 次 |
| 最近记录: |