Bad Spectrum from Android FFT-Output (Visualiser)?

I have some question about FFT (in fact, I believe this is more about the Androids FFT output from Visualizer.getFFT ()).

I created a Music Player with its own library function for Android, including many materials (such as genres, dynamic playlists, and visualizations). I currently have some visualization issues that I create when it comes to providing a spectrum of the current AudioStream.

I already read the following questions (and answers) to get the idea of ​​FFT androids:

What kind of output should I see from getFft?

Android 2.3 Visualizer - understanding getFft () problems

Now to my problem: The spectrum that I get from the getFFTs coefficients seems a bit "weird." I notice that the spectrum I render seems to display a lot of “noise” when playing a song, so I tried using some test sounds. One of them is a simple 8 kHz sound, which should lead to one peak on the graph. Unfortunately, the result is as follows:

http://img4.imageshack.us/img4/4181/spectrum8khz.png

The noise that appears below flickers across the entire width of the graph. High bars remain in a slightly flickering position.

When I use a test sound that moves slowly from 1 kHz to 20 kHz, it looks like this (about 2-3 kHz):

http://img846.imageshack.us/img846/7373/spectrum3khz1khz20khz.png

Peaks move from left to right, and each of them is a little faster, so the distance between the peaks increases over time. What is not visible is that the peaks return and go from right to left when they leave the screen on the right (but with a smaller value). Also, all peaks join one large peak for a little more than 0.5 screen.

Here is the code I use to retrieve the data:

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; } 

In the code above, mRawSpecData is the result of the visualisers getFFT () function. The length of the captured data is 1024. Currently, the slope starts at 1 because mRawSpecData [0] contains DC and mRawSpecData [1] contains n / 2.

To solve my problem, I also tried to integrate with DC and hopper phase. I thought maybe I had to apply some calculations by values ​​to “clear” the graph. But I did not succeed (maybe because I did not understand what was going on with the DC / phase!).

I spent two weeks searching Google in the evenings and tried different calculations, but nothing helped.

So what is the deal? Am I doing something wrong or am I going out? After that, another question that bothers me is how to scale the values ​​correctly. My goal is to get values ​​between 0f and 1f.

thanks a lot

rampage

PS: Screenshots taken via eclipse from a phone running Android 2.3.

PPS: I also tested sounds with various other players (like winamp), and there I see the correct spectrum behavior.

+4
source share
1 answer

I have a good result using the following calculations to get a visualizer such as this image. I use almost 19 images to display like this. They respond to the input of the getFFT () method. And be sure to turn on both the equalizer and the visualizer. Otherwise, it gives high values, and fft values ​​correspond to the volume of the device. In fact, I cannot give an explanation of the code because of my english.so in the last code here.

VisualizerView:

 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(); } } 

In 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); 
+4
source

Source: https://habr.com/ru/post/1342727/


All Articles