Creating graph of spectrogram in android using mus

2020-08-01 11:53发布

问题:

I am attempting to create a spectrogram visualisation in Android. I use the android device to record sound in .PCM format and then convert this to .WAV so that it can be analysed using the musicg library https://code.google.com/p/musicg/.

Using musicg I can create a spectrogram of the recorded .WAV and from this spectrogram I can extract the frequency time domain data as a double[][].

What I am trying to work out next is how to visualise this data in Android. Any help would be appreciated.

Following user3161880 answer, I have tried the following but I am not getting anything drawn to screen. I can draw a circle as shown in user3161880 answer. Any ideas why this wouldn't work?

private static class SpectrogramView extends View {
        private Paint paint = new Paint();
        private double [][] data;

        public SpectrogramView(Context context, double [][] data) {
            super(context);
            this.data = data;
        }

        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);

            if (data != null) {
                paint.setStrokeWidth(1);
                canvas.drawColor(Color.WHITE);
                int width = data.length;
                int height = data[0].length;
                for(int i = 0; i < width; i++) {
                    for(int j = 0; j < height; j++) {
                        int value;
                        value = 255 - (int)(data[i][j] * 255);
                        paint.setColor(value<<16|value<<8|value|255<<24);
                        canvas.drawPoint(i, height-1-j, paint);
                    }
                }

            } else {
                System.err.println("Data Corrupt");
            }

            //draw circle
            /*paint.setColor(Color.RED);
            canvas.drawColor(Color.BLUE);
            canvas.drawCircle(100.0f, 100.0f, 50.0f, paint);*/
        }
    }

回答1:

An improved answer than in my original post.

private static class SpectrogramView extends View {
    private Paint paint = new Paint();
    private Bitmap bmp;

    public SpectrogramView(Context context, double [][] data) {
        super(context);

        if (data != null) {
            paint.setStrokeWidth(1);
            int width = data.length;
            int height = data[0].length;

        int[] arrayCol = new int[width*height];
        int counter = 0;
        for(int i = 0; i < height; i++) {
            for(int j = 0; j < width; j++) {
                int value;
                int color;
                value = 255 - (int)(data[j][i] * 255);
                color = (value<<16|value<<8|value|255<<24);
                arrayCol[counter] = color;
                counter ++;
            }
        }
        bmp = Bitmap.createBitmap(arrayCol, width, height, Config.ARGB_8888);

        } else {
            System.err.println("Data Corrupt");
        }
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        canvas.drawBitmap(bmp, 0, 100, paint);
    }
}

This will improve performance by creating a bitmap before drawing to canvas.



回答2:

If you are willing to show the still spectrogram of the prerecorded audio, a simple View would suffice for you. You can override onDraw method of the view. Here you will get access to the Canvas on which the background will be drawn.

What remains is your display logic, which maps double to color and time-frequency grid to x-y co-ordinates of the canvas.

public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(new MyView(this));
    }

    private static class MyView extends View {

        Paint paint = new Paint();

        public MyView(Context context) {
            super(context);
        }

        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);

            // draw circle
            paint.setColor(Color.RED);
            canvas.drawColor(Color.BLUE);
            canvas.drawCircle(100.f, 100.f, 50.f, paint);
        }

    }
}