• SurfaceView绘制录音波形图


    本文简单记录由View绘制转为SurfaceView绘制的波形图问题.

    上代码:

      1 public class VoiceLineView extends View {
      2     private final int LINE = 0;
      3     private final int RECT = 1;
      4 
      5     private int middleLineColor = Color.BLACK;
      6     private int voiceLineColor = Color.BLACK;
      7     private float middleLineHeight = 4;
      8     private Paint paint;
      9     private Paint paintVoicLine; 11     /**
     12      * 灵敏度
     13      */
     14     private int sensibility = 4;
     15 
     16     private float maxVolume = 100;
     17 
     18 
     19     private float translateX = 0;
     20     private boolean isSet = false;
     21 
     22     /**
     23      * 振幅
     24      */
     25     private float amplitude = 1;
     26     /**
     27      * 音量
     28      */
     29     private float volume = 10;
     30     private int fineness = 1;
     31     private float targetVolume = 1;
     32 
     33 
     34     private long speedY = 50;
     35     private float rectWidth = 25;
     36     private float rectSpace = 5;
     37     private float rectInitHeight = 4;
     38     private List<Rect> rectList;
     39 
     40     private long lastTime = 0;
     41     private int lineSpeed = 90;
     42 
     43     List<Path> paths = null;
     44 
     45     public VoiceLineView(Context context) {
     46         super(context);
     47     }
     48 
     49     public VoiceLineView(Context context, AttributeSet attrs) {
     50         super(context, attrs);
     51         initAtts(context, attrs);
     52     }
     53 
     54     public VoiceLineView(Context context, AttributeSet attrs, int defStyleAttr) {
     55         super(context, attrs, defStyleAttr);
     56         initAtts(context, attrs);
     57     }
     58 
     59     private void initAtts(Context context, AttributeSet attrs) {
     60         TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.voiceView);
     61         mode = typedArray.getInt(R.styleable.voiceView_viewMode, 0);
     62         voiceLineColor = typedArray.getColor(R.styleable.voiceView_voiceLine, Color.BLACK);
     63         maxVolume = typedArray.getFloat(R.styleable.voiceView_maxVolume, 100);
     64         sensibility = typedArray.getInt(R.styleable.voiceView_sensibility, 4);
     65         if (mode == RECT) {
     66             rectWidth = typedArray.getDimension(R.styleable.voiceView_rectWidth, 25);
     67             rectSpace = typedArray.getDimension(R.styleable.voiceView_rectSpace, 5);
     68             rectInitHeight = typedArray.getDimension(R.styleable.voiceView_rectInitHeight, 4);
     69         } else {
     70             middleLineColor = typedArray.getColor(R.styleable.voiceView_middleLine, Color.BLACK);
     71             middleLineHeight = typedArray.getDimension(R.styleable.voiceView_middleLineHeight, 4);
     72             lineSpeed = typedArray.getInt(R.styleable.voiceView_lineSpeed, 90);
     73             fineness = typedArray.getInt(R.styleable.voiceView_fineness, 1);
     74             paths = new ArrayList<>(20);
     75             for (int i = 0; i < 20; i++) {
     76                 paths.add(new Path());
     77             }
     78         }
     79         typedArray.recycle();
     80     }
     81 
     82     @Override
     83     protected void onDraw(Canvas canvas) { 87             drawMiddleLine(canvas);
     88             drawVoiceLine(canvas); 90             run();
     91     }
     92 
     93     private void drawMiddleLine(Canvas canvas) {
     94         if (paint == null) {
     95             paint = new Paint();
     96             paint.setColor(middleLineColor);
     97             paint.setAntiAlias(true);
     98         }
     99         canvas.save();
    100         canvas.drawRect(0, getHeight() / 2 - middleLineHeight / 2, getWidth(), getHeight() / 2 + middleLineHeight / 2, paint);
    101         canvas.restore();
    102     }
    103 
    104     private void drawVoiceLine(Canvas canvas) {
    105         lineChange();
    106         if (paintVoicLine == null) {
    107             paintVoicLine = new Paint();
    108             paintVoicLine.setColor(voiceLineColor);
    109             paintVoicLine.setAntiAlias(true);
    110             paintVoicLine.setStyle(Paint.Style.STROKE);
    111             paintVoicLine.setStrokeWidth(2);
    112         }
    113         canvas.save();
    114         int moveY = getHeight() / 2;
    115         for (int i = 0; i < paths.size(); i++) {
    116             paths.get(i).reset();
    117             paths.get(i).moveTo(getWidth(), getHeight() / 2);
    118         }
    119         for (float i = getWidth() - 1; i >= 0; i -= fineness) {
    120             amplitude = 4 * volume * i / getWidth() - 4 * volume * i * i / getWidth() / getWidth();
    121             for (int n = 1; n <= paths.size(); n++) {
    122                 float sin = amplitude * (float) Math.sin((i - Math.pow(1.22, n)) * Math.PI / 180 - translateX);
    123                 paths.get(n - 1).lineTo(i, (2 * n * sin / paths.size() - 15 * sin / paths.size() + moveY));
    124             }
    125         }
    126         for (int n = 0; n < paths.size(); n++) {
    127             if (n == paths.size() - 1) {
    128                 paintVoicLine.setAlpha(255);
    129             } else {
    130                 paintVoicLine.setAlpha(n * 130 / paths.size());
    131             }
    132             if (paintVoicLine.getAlpha() > 0) {
    133                 canvas.drawPath(paths.get(n), paintVoicLine);
    134             }
    135         }
    136         canvas.restore();
    137     }
    138 
    139   167 
    168     public void setVolume(int volume) {
    169         if (volume > maxVolume * sensibility / 25) {
    170             isSet = true;
    171             this.targetVolume = getHeight() * volume / 2 / maxVolume;
    172         }
    173     }
    174 
    175     private void lineChange() {
    176         if (lastTime == 0) {
    177             lastTime = System.currentTimeMillis();
    178             translateX += 1.5;
    179         } else {
    180             if (System.currentTimeMillis() - lastTime > lineSpeed) {
    181                 lastTime = System.currentTimeMillis();
    182                 translateX += 1.5;
    183             } else {
    184                 return;
    185             }
    186         }
    187         if (volume < targetVolume && isSet) {
    188             volume += getHeight() / 30;
    189         } else {
    190             isSet = false;
    191             if (volume <= 10) {
    192                 volume = 10;
    193             } else {
    194                 if (volume < getHeight() / 30) {
    195                     volume -= getHeight() / 60;
    196                 } else {
    197                     volume -= getHeight() / 30;
    198                 }
    199             }
    200         }
    201     }
    202 
    221     public void run() {225             invalidate();227     }
    228 
    229 }

    上面是View的canvas实现的波形图绘制,cpu占用率比较高,在20%左右,一边录音一边绘制,手机发烫是最明显的感觉了.

    下面我们换成SurfaceView绘制的

    public class VoiceLineSurfaceView extends SurfaceView implements Runnable,SurfaceView.Callback {
        private final int LINE = 0;
        private final int RECT = 1;
    
        private int middleLineColor = Color.BLACK;
        private int voiceLineColor = Color.BLACK;
        private float middleLineHeight = 4;
        private Paint paint;
        private Paint paintVoicLine;/**
         * 灵敏度
         */
        private int sensibility = 4;
    
        private float maxVolume = 100;
    
    
        private float translateX = 0;
        private boolean isSet = false;
    
        /**
         * 振幅
         */
        private float amplitude = 1;
        /**
         * 音量
         */
        private float volume = 10;
        private int fineness = 1;
        private float targetVolume = 1;
    
    
        private long speedY = 50;
        private float rectWidth = 25;
        private float rectSpace = 5;
        private float rectInitHeight = 4;
        private List<Rect> rectList;
    
        private long lastTime = 0;
        private int lineSpeed = 90;
       private SurfaceHolder surfaceHolder;
        List<Path> paths = null;
    private boolean isWaveDrawing = false;
    private boolean isMiddleLineDrawing = true;
    private Thread thread;
    private Canvas canvas;
    
    public VoiceLineSurfaceView(Context context) {
            super(context);
        }
    
        public VoiceLineSurfaceView(Context context, AttributeSet attrs) {
            super(context, attrs);
            initAtts(context, attrs);
        }
    
        public VoiceLineSurfaceView(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            initAtts(context, attrs);
        }
    
        private void initAtts(Context context, AttributeSet attrs) {
            TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.voiceView);
            mode = typedArray.getInt(R.styleable.voiceView_viewMode, 0);
            voiceLineColor = typedArray.getColor(R.styleable.voiceView_voiceLine, Color.BLACK);
            maxVolume = typedArray.getFloat(R.styleable.voiceView_maxVolume, 100);
            sensibility = typedArray.getInt(R.styleable.voiceView_sensibility, 4);
                middleLineColor = typedArray.getColor(R.styleable.voiceView_middleLine, Color.BLACK);
                middleLineHeight = typedArray.getDimension(R.styleable.voiceView_middleLineHeight, 4);
                lineSpeed = typedArray.getInt(R.styleable.voiceView_lineSpeed, 90);
                fineness = typedArray.getInt(R.styleable.voiceView_fineness, 1);
                paths = new ArrayList<>(20);
                for (int i = 0; i < 20; i++) {
                    paths.add(new Path());
                }
            typedArray.recycle();
        setZOrderOnTop(true);
        getHolder().setFormat(PixelFormat.TRANSLUENT);
        surfaceHolder =  getHolder();
        surfaceHolder.addCallback(this);
        }
    private void drawMiddleLine(Canvas canvas) {
            if (paint == null) {
                paint = new Paint();
                paint.setColor(middleLineColor);
                paint.setAntiAlias(true);
            }
            canvas.save();
            canvas.drawRect(0, getHeight() / 2 - middleLineHeight / 2, getWidth(), getHeight() / 2 + middleLineHeight / 2, paint);
            canvas.restore();
        }
    
        private void drawVoiceLine(Canvas canvas) {
            lineChange();
            if (paintVoicLine == null) {
                paintVoicLine = new Paint();
                paintVoicLine.setColor(voiceLineColor);
                paintVoicLine.setAntiAlias(true);
                paintVoicLine.setStyle(Paint.Style.STROKE);
                paintVoicLine.setStrokeWidth(2);
            }
            canvas.save();
            int moveY = getHeight() / 2;
            for (int i = 0; i < paths.size(); i++) {
                paths.get(i).reset();
                paths.get(i).moveTo(getWidth(), getHeight() / 2);
            }
            for (float i = getWidth() - 1; i >= 0; i -= fineness) {
                amplitude = 4 * volume * i / getWidth() - 4 * volume * i * i / getWidth() / getWidth();
                for (int n = 1; n <= paths.size(); n++) {
                    float sin = amplitude * (float) Math.sin((i - Math.pow(1.22, n)) * Math.PI / 180 - translateX);
                    paths.get(n - 1).lineTo(i, (2 * n * sin / paths.size() - 15 * sin / paths.size() + moveY));
                }
            }
            for (int n = 0; n < paths.size(); n++) {
                if (n == paths.size() - 1) {
                    paintVoicLine.setAlpha(255);
                } else {
                    paintVoicLine.setAlpha(n * 130 / paths.size());
                }
                if (paintVoicLine.getAlpha() > 0) {
                    canvas.drawPath(paths.get(n), paintVoicLine);
                }
            }
            canvas.restore();
        }
    public void setVolume(int volume) {
            if (volume > maxVolume * sensibility / 25) {
                isSet = true;
                this.targetVolume = getHeight() * volume / 2 / maxVolume;
            }
        }
    
        private void lineChange() {
            if (lastTime == 0) {
                lastTime = System.currentTimeMillis();
                translateX += 1.5;
            } else {
                if (System.currentTimeMillis() - lastTime > lineSpeed) {
                    lastTime = System.currentTimeMillis();
                    translateX += 1.5;
                } else {
                    return;
                }
            }
            if (volume < targetVolume && isSet) {
                volume += getHeight() / 30;
            } else {
                isSet = false;
                if (volume <= 10) {
                    volume = 10;
                } else {
                    if (volume < getHeight() / 30) {
                        volume -= getHeight() / 60;
                    } else {
                        volume -= getHeight() / 30;
                    }
                }
            }
        }
    @Override
    public void surfaceCreated(){
    }
    @Override
    public void surfaceChanged(){
    isMiddleLineDrawing = true;
    thread = new Thread(this);
    thread.start();
    }
    @Override
    public void surfaceDestroyed(){
    isMiddleLineDrawing = false;
    }
    @Override
    public void run() {
      while(isMiddleLineDrawing){
        canvas = surfaceHolder.lockCanvas();
        if(canvas==null){
        return;
        }
        canvas.drawColor(Color.TRANSLUENT,PorterDuff.Mode.CLEAR);
        if(isWaveDrawing){
        drawVoiceLine(canvas);
        }
        drawMiddleLine(canvas);
        surfaceHolder.unlockCanvasAndPost(canvas);
      }
     }
    
    public void setDrawing(boolean drawing){
      isMiddleLineDrawing = true;
      isWaveDrawing = drawing;
    }
    
    }
  • 相关阅读:
    自定义Web框架
    Python四种实现单例模式的方法
    popup的简单应用举例
    前端框架之BootStrap的简单介绍
    前端之JQuery:JQuery扩展和事件
    前端之JQuery:JQuery文档操作
    前端之JQuery:JQuery属性操作
    前端之JQuery:JQuery基本语法
    MinerDB.java 数据库工具类
    MinerConstanits.java 常量类
  • 原文地址:https://www.cnblogs.com/fuyaozhishang/p/9165569.html
Copyright © 2020-2023  润新知