123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202 |
- package com.cooleshow.musicmerge.widget;
- import android.content.Context;
- import android.content.res.TypedArray;
- import android.graphics.Canvas;
- import android.graphics.Color;
- import android.graphics.Paint;
- import android.graphics.Path;
- import android.graphics.RectF;
- import android.media.audiofx.Visualizer;
- import android.util.AttributeSet;
- import android.view.View;
- import com.cooleshow.base.utils.LOG;
- import com.cooleshow.base.utils.SizeUtils;
- import com.cooleshow.musicmerge.R;
- import androidx.annotation.Nullable;
- /**
- *
- * on 2021/4/13
- * 自定义组件:音乐频谱显示组件
- * API-> setMediaPlayer() 外层设置路径 播放之后 自动显示频谱效果
- */
- public class MusicFrequencyView extends View {
- private static final String TAG = "MusicFrequencyView";
- private int LUMP_COUNT = 120;
- private int LUMP_WIDTH = SizeUtils.dp2px(1.5f);
- ;
- private int LUMP_SPACE = SizeUtils.dp2px(3);
- private int LUMP_SIZE = LUMP_WIDTH + LUMP_SPACE;
- private int LUMP_MAX_HEIGHT = SizeUtils.dp2px(80);
- private int LUMP_MIN_HEIGHT = SizeUtils.dp2px(3);
- private float SCALE = 0.95f;
- private int widthsize;
- private int heightsize;
- private Visualizer visualizer;
- private int itemColor = Color.WHITE;
- private Paint paint1;
- protected RectF mRect;
- public MusicFrequencyView(Context context, @Nullable AttributeSet attrs) {
- super(context, attrs);
- TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.musicView);
- itemColor = ta.getColor(R.styleable.musicView_itemColor, Color.WHITE);
- mRect = new RectF();
- waveData = new float[LUMP_COUNT];
- }
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- widthsize = MeasureSpec.getSize(widthMeasureSpec);
- heightsize = MeasureSpec.getSize(heightMeasureSpec);
- setMeasuredDimension(widthsize, heightsize);
- init();
- }
- @Override
- protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
- super.onLayout(changed, left, top, right, bottom);
- mRect.set(0, 0, getWidth(), getHeight());
- }
- @Override
- protected void onDraw(Canvas canvas) {
- super.onDraw(canvas);
- //因为外部宽度是写死的,不调整坐标算法,最后一个可能绘制不全,暂时不绘制最后一个吧
- for (int i = 1; i <= LUMP_COUNT-1; i++) {
- // canvas.drawLine(mRect.width() * i / LUMP_COUNT, mRect.height() / 2, mRect.width() * i / LUMP_COUNT, -LUMP_MIN_HEIGHT + mRect.height() / 2 - SCALE * waveData[i], paint1);
- // canvas.drawLine(mRect.width() * i / LUMP_COUNT, mRect.height() / 2, mRect.width() * i / LUMP_COUNT, LUMP_MIN_HEIGHT + mRect.height() / 2 + SCALE * waveData[i], paint1);
- canvas.drawLine(mRect.width() * i / LUMP_COUNT, -LUMP_MIN_HEIGHT + mRect.height() / 2 - SCALE * waveData[i-1], mRect.width() * i / LUMP_COUNT, LUMP_MIN_HEIGHT + mRect.height() / 2 + SCALE * waveData[i - 1], paint1);
- }
- }
- private Path getPath(float startX, float startY, float endX, float endY, Paint paint) {
- Path path = new Path();
- paint.setStrokeCap(Paint.Cap.SQUARE);
- path.moveTo(startY, startY);
- path.lineTo(endX / 2, endY / 2);
- paint.setStrokeCap(Paint.Cap.ROUND);
- path.lineTo(endX, endY);
- return path;
- }
- private Visualizer.OnDataCaptureListener dataCaptureListener = new Visualizer.OnDataCaptureListener() {
- @Override
- public void onWaveFormDataCapture(Visualizer visualizer, byte[] waveform, int samplingRate) {
- }
- @Override
- public void onFftDataCapture(Visualizer visualizer, byte[] fft, int samplingRate) {
- setWaveData(fft);
- }
- };
- private float[] waveData;
- private void setWaveData(byte[] fft) {
- waveData = readyData(fft);
- // LOG.i(TAG, "setWaveData:" + waveData);
- invalidate();
- }
- /**
- * 预处理数据
- *
- * @return
- */
- private float[] readyData(byte[] fft) {
- float[] model = new float[fft.length / 2 + 1];
- model[0] = (float) Math.abs(fft[1]);
- int j = 1;
- for (int i = 2; i < LUMP_COUNT * 2; ) {
- model[j] = (float) Math.hypot(fft[i], fft[i + 1]);
- i += 2;
- j++;
- model[j] = Math.abs(model[j]);
- }
- // LOG.i(TAG,"model:"+model.length);
- float[] results = hananianWindow(model, 2);
- // LOG.i(TAG,"results:"+results.length);
- return results;
- }
- public static float[] hananianWindow(float[] data, int windowSize) {
- float[] windowData = new float[data.length - windowSize + 1];
- for (int i = 0; i < windowData.length; i++) {
- float sum = 0;
- for (int j = 0; j < windowSize; j++) {
- sum += data[i + j];
- }
- windowData[i] = sum / windowSize;
- }
- return windowData;
- }
- /**
- * 只需传入 mediaPlayer 即可
- *
- * @param
- */
- public void setMediaPlayer(final int audioSessionId) {
- try {
- if (visualizer == null) {
- visualizer = new Visualizer(audioSessionId);
- int captureSize = Visualizer.getCaptureSizeRange()[1];
- int captureRate = Visualizer.getMaxCaptureRate() / 2;
- // 3:设置参数
- visualizer.setCaptureSize(captureSize);
- visualizer.setDataCaptureListener(dataCaptureListener, captureRate, false, true);
- visualizer.setScalingMode(Visualizer.SCALING_MODE_NORMALIZED);
- visualizer.setEnabled(true);
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- public void setVisualizerEnable(boolean isEnable) {
- if (visualizer != null) {
- visualizer.setEnabled(isEnable);
- }
- }
- public void release() {
- if (visualizer != null) {
- visualizer.release();
- }
- }
- /**
- * 设置频率数据
- *
- * @param data
- */
- public void setMusicData(int[] data) {
- }
- /**
- * 初始化画笔
- */
- void init() {
- paint1 = new Paint();
- paint1.setStrokeWidth(LUMP_WIDTH);
- paint1.setColor(itemColor);
- paint1.setStrokeCap(Paint.Cap.ROUND);
- paint1.setAntiAlias(true);
- paint1.setStyle(Paint.Style.FILL);
- paint1.setStrokeJoin(Paint.Join.BEVEL);
- // paint1.setMaskFilter(new BlurMaskFilter(5, BlurMaskFilter.Blur.SOLID));
- }
- }
|