Espectro malo de la salida FFT de Android (Visualiser)?
Tengo algún tipo de pregunta sobre FFT (En realidad creo que es más acerca de Androids FFT-Salida de Visualizer.getFFT ()).
He creado un reproductor de música con función de biblioteca propia para Android, incluyendo lotes de cosas (como géneros, listas de reproducción dinámicas y visualizaciones). Actualmente tengo algunos problemas con las visualizaciones que crear cuando se trata de hacer un espectro de la AudioStream actual.
- ¿Cómo convertir la matriz de bytes de audio PCM de 16 bits a una matriz doble o flotante?
- Biblioteca FFT en android Sdk
- FFT en la señal EEG en Android comprensión del código
- Generación de coeficientes de filtro DSP en C / Java para convolución en el dominio del tiempo
- La instancia de audiorecord de Android falla
Ya leí las siguientes preguntas (y respuestas) para obtener una idea de Androids FFT:
¿Qué tipo de salida debo ver de getFft?
Android 2.3 Visualizer – Problemas para entender getFft ()
Ahora a mi problema: El espectro que consigo de los coeficientes de los getFFTs parece ser algo "impar". Noto que el espectro que hago parece mostrar mucho "ruido" cuando toco una canción así que intenté usar algunos sonidos de prueba. Uno de ellos es un simple sonido de 8khz que debería dar como resultado sólo un pico en el gráfico. Desafortunadamente, el resultado es similar al siguiente:
Http://img4.imageshack.us/img4/4181/spectrum8khz.png
El ruido que aparece en la parte inferior está parpadeando por todo el ancho de la gráfica. Las barras altas permanecen en posición sólo parpadeando ligeramente en magnitud.
Cuando uso un sonido de prueba moviéndose lentamente de 1kHz a 20kHz, parece que lo siguiente (a unos 2-3kHz):
Http://img846.imageshack.us/img846/7373/spectrum3khz1khz20khz.png
Los picos se mueven de izquierda a derecha y cada uno es un poco más rápido, así que con el tiempo la distancia entre los picos crece. Lo que no es visible es que los picos vuelven y van de derecha a izquierda una vez que salen de la pantalla a la derecha (pero con menor magnitud). También todos los picos se unen a un gran pico en un poco más de 0,5 de la pantalla.
Aquí está el código que utilizo para recuperar los datos:
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; }
En el código anterior mRawSpecData es el resultado de la función de los visores getFFT (). La longitud de los datos capturados es 1024. Actualmente la pendiente comienza en 1 porque mRawSpecData [0] contiene la DC y mRawSpecData [1] contiene n / 2.
Para solucionar mi problema también traté de jugar con la DC y la fase de la frecuencia-bin. Quizás tuve que aplicar algún cálculo sobre las magnitudes para "limpiar" el gráfico. Pero no tuve éxito (Tal vez porque no he conseguido lo que es goind con DC / fase en absoluto!).
Me pasé dos semanas buscando google por las noches y probar diferentes cálculos pero nada realmente ayudó.
Entonces, ¿cuál es el trato? ¿Estoy haciendo algo mal o dejando algo fuera? Después de eso otra pregunta que me molesta es cómo escalar las magnitudes correctamente. Mi objetivo es obtener valores entre 0f y 1f.
Muchas gracias
alboroto
PS: Capturas de pantalla tomadas a través de eclipse desde un teléfono con Android 2.3.
PPS: También he comprobado los sonidos con varios otros jugadores (como winamp) y allí veo el comportamiento correcto del espectro.
- ¿Cuántas FFT por segundo puedo hacer en mi teléfono inteligente? (Para realizar reconocimiento de voz)
- ¿Cómo puedo usar la convolución rápida basada en FFT para implementar un LPF si la convolución rápida requiere un LPF?
- ¿Cómo obtener la frecuencia del resultado fft?
- Cálculo de la transformación de Fourier en Java
- Transformación de Fourier rápida en Java
- ¿Por qué mi FFT ofrece una salida de visualizador diferente de Windows Media Player?
- ¿Cuál es la biblioteca FFT más rápida para dispositivos iOS / Android ARM?
- Uso de getSpectrum () en la librería Libgdx
Tengo buen resultado usando cálculos siguientes, para obtener un visualizador como esta imagen. Estoy utilizando cerca de 19 imágenes para mostrar como this.Thats están respondiendo por las entradas de método getFFT (). Y asegúrese de habilitar tanto el ecualizador y el visualizador, de lo contrario da valores altos y fft valores se responde al volumen del dispositivo.Actualmente no soy capaz Para dar la explicación del código debido a mi código pasado de english.so i aquí.
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(); } }
En 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);
- Android Development: Cambio del brillo de la pantalla en el servicio
- Descargar archivo pdf y guardar en tarjeta SD