4

FFT についていくつか質問があります (実際には、Visualizer.getFFT() からの Android の FFT 出力に関するものだと思います)。

Android 用の独自のライブラリ機能を備えた Music-Player を作成しました。これには、多くのもの (ジャンル、動的プレイリスト、視覚化など) が含まれます。現在、現在の AudioStream のスペクトルをレンダリングする際に、作成した視覚化に問題があります。

Android FFT のアイデアを得るために、次の質問 (および回答) を既に読みました。

getFft からどのような出力が表示されますか?

Android 2.3 ビジュアライザー - getFft() を理解できない

今私の問題に: getFFTs 係数から取得したスペクトルは、やや「奇数」のようです。曲を再生すると、レンダリングしたスペクトルに多くの「ノイズ」が表示されるように見えるので、いくつかのテスト サウンドを使用してみました。そのうちの 1 つは単純な 8khz サウンドで、グラフのピークが 1 つだけになるはずです。残念ながら、結果は次のようになります。

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

下部に現れるノイズは、グラフの幅全体でちらつきます。高いバーは位置にとどまり、大きさがわずかにちらつくだけです。

1kHz から 20kHz までゆっくりと移動するテスト サウンドを使用すると、次のようになります (約 2 ~ 3kHz で)。

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

ピークは左から右に移動し、それぞれが少し速くなるため、時間の経過とともにピーク間の距離が大きくなります。表示されていないのは、ピークが画面の右側を離れると、ピークが戻ってきて右から左に移動することです (ただし、マグニチュードは小さくなります)。また、すべてのピークが画面の 0.5 強で 1 つの大きなピークに結合します。

データを取得するために使用するコードは次のとおりです。

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

上記のコードでは、mRawSpecData は Visualisers の getFFT() 関数の結果です。キャプチャされたデータの長さは 1024 です。現在、mRawSpecData[0] には DC が含まれ、mRawSpecData[1] には n/2 が含まれているため、傾きは 1 から始まります。

私の問題を解決するために、周波数ビンのDCと位相をいじろうとしました。グラフを「きれいにする」ために、マグニチュードに計算を適用する必要があるかもしれないと思いました。しかし、私は成功しませんでした (おそらく、DC/フェーズで何が起こっているのかまったくわからなかったからです!)。

夕方にグーグルを検索し、さまざまな計算を試すのに2週間費やしましたが、実際には何も役に立ちませんでした.

それで、取引は何ですか?私は何か間違ったことをしているのですか、それとも何かを省略していますか? その後、私を悩ませている別の質問は、マグニチュードを正しくスケーリングする方法です。私の目標は、0f と 1f の間の値を取得することです。

どうもありがとう

大暴れ

PS: Android 2.3 を実行している携帯電話から eclipse を介して取得したスクリーンショット。

PPS: また、他のさまざまなプレイヤー (winamp など) でサウンドをチェックしたところ、スペクトルの正しい動作が見られました。

4

1 に答える 1

4

この画像のようなビジュアライザーを取得するには、次の計算を使用して良い結果が得られます。私はこのように表示するために19近くの画像を使用しています。これらはgetFFT()メソッド入力によって応答しています。また、イコライザーとビジュアライザーの両方を有効にしてください。そうでない場合は、高い値が得られ、fft値はデバイスのボリュームに応答します。実際にはできません。私のenglish.soのためにコードの説明をするために、私はここにコードを置きました。

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

    }

}

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);
于 2011-11-26T10:55:44.917 に答える