android 实现跳动频谱 DEMO

package com.terry.AudioFx;

import android.app.Activity;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnCompletionListener;
import android.media.audiofx.Equalizer;
import android.media.audiofx.Visualizer;
import android.media.audiofx.Visualizer.OnDataCaptureListener;
import android.os.Bundle;
import android.util.Log;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.SeekBar;
import android.widget.TextView;
import android.widget.SeekBar.OnSeekBarChangeListener;

public class AudioFxActivity extends Activity {

    private static final String TAG = "AudioFxActivity";

    private static final float VISUALIZER_HEIGHT_DIP = 50f;

    private MediaPlayer mMediaPlayer;
    private Visualizer mVisualizer;
    private Equalizer mEqualizer; // 均衡器

    private LinearLayout mLayout;
    VisualizerView mVisualizerView;
    private TextView mStatusTextView;

    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setVolumeControlStream(AudioManager.STREAM_MUSIC);

        mStatusTextView = new TextView(this);
        mLayout = new LinearLayout(this);
        mLayout.setOrientation(LinearLayout.VERTICAL);
        mLayout.addView(mStatusTextView);
        setContentView(mLayout);

        mMediaPlayer = MediaPlayer.create(this, R.raw.z8806c);

        setupVisualizerFxAndUi();
        setupEqualizeFxAndUi();

        mVisualizer.setEnabled(true);
        mMediaPlayer.setOnCompletionListener(new OnCompletionListener() {

            @Override
            public void onCompletion(MediaPlayer mp) {
                // TODO Auto-generated method stub
                mVisualizer.setEnabled(false);
            }
        });

        mMediaPlayer.start();
        mStatusTextView.setText("播放中。。。");
    }

    /**
     * 通过mMediaPlayer返回的AudioSessionId创建一个优先级为0均衡器对象 并且通过频谱生成相应的UI和对应的事件
     */
    private void setupEqualizeFxAndUi() {
        mEqualizer = new Equalizer(0, mMediaPlayer.getAudioSessionId());
        mEqualizer.setEnabled(true);// 启用均衡器
        TextView eqTextView = new TextView(this);
        eqTextView.setText("均衡器:");
        mLayout.addView(eqTextView);

        // 通过均衡器得到其支持的频谱引擎
        short bands = mEqualizer.getNumberOfBands();

        // getBandLevelRange 是一个数组,返回一组频谱等级数组,
        // 第一个下标为最低的限度范围
        // 第二个下标为最大的上限,依次取出
        final short minEqualizer = mEqualizer.getBandLevelRange()[0];
        final short maxEqualizer = mEqualizer.getBandLevelRange()[1];

        for (short i = 0; i < bands; i++) {
            final short band = i;

            TextView freqTextView = new TextView(this);
            freqTextView.setLayoutParams(new ViewGroup.LayoutParams(
                    ViewGroup.LayoutParams.FILL_PARENT,
                    ViewGroup.LayoutParams.WRAP_CONTENT));

            freqTextView.setGravity(Gravity.CENTER_HORIZONTAL);

            // 取出中心频率
            freqTextView
                    .setText((mEqualizer.getCenterFreq(band) / 1000) + "HZ");
            mLayout.addView(freqTextView);

            LinearLayout row = new LinearLayout(this);
            row.setOrientation(LinearLayout.HORIZONTAL);

            TextView minDbTextView = new TextView(this);
            minDbTextView.setLayoutParams(new ViewGroup.LayoutParams(
                    ViewGroup.LayoutParams.WRAP_CONTENT,
                    ViewGroup.LayoutParams.WRAP_CONTENT));

            minDbTextView.setText((minEqualizer / 100) + " dB");

            TextView maxDbTextView = new TextView(this);
            maxDbTextView.setLayoutParams(new ViewGroup.LayoutParams(
                    ViewGroup.LayoutParams.WRAP_CONTENT,
                    ViewGroup.LayoutParams.WRAP_CONTENT));
            maxDbTextView.setText((maxEqualizer / 100) + " dB");

            LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(
                    ViewGroup.LayoutParams.FILL_PARENT,
                    ViewGroup.LayoutParams.WRAP_CONTENT);

            layoutParams.weight = 1;

            SeekBar seekbar = new SeekBar(this);
            seekbar.setLayoutParams(layoutParams);
            seekbar.setMax(maxEqualizer - minEqualizer);
            seekbar.setProgress(mEqualizer.getBandLevel(band));

            seekbar.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {

                @Override
                public void onStopTrackingTouch(SeekBar seekBar) {
                }

                @Override
                public void onStartTrackingTouch(SeekBar seekBar) {
                }

                @Override
                public void onProgressChanged(SeekBar seekBar, int progress,
                        boolean fromUser) {
                    // TODO Auto-generated method stub
                    mEqualizer.setBandLevel(band,
                            (short) (progress + minEqualizer));
                }
            });
            row.addView(minDbTextView);
            row.addView(seekbar);
            row.addView(maxDbTextView);

            mLayout.addView(row);
        }

    }

    /**
     * 生成一个VisualizerView对象,使音频频谱的波段能够反映到 VisualizerView上
     */
    private void setupVisualizerFxAndUi() {
        mVisualizerView = new VisualizerView(this);
        mVisualizerView.setLayoutParams(new ViewGroup.LayoutParams(
                ViewGroup.LayoutParams.FILL_PARENT,
                (int) (VISUALIZER_HEIGHT_DIP * getResources()
                        .getDisplayMetrics().density)));
        mLayout.addView(mVisualizerView);

        mVisualizer = new Visualizer(mMediaPlayer.getAudioSessionId());
        // 参数内必须是2的位数
        mVisualizer.setCaptureSize(Visualizer.getCaptureSizeRange()[1]);

        // 设置允许波形表示,并且捕获它
        mVisualizer.setDataCaptureListener(new OnDataCaptureListener() {

            @Override
            public void onWaveFormDataCapture(Visualizer visualizer,
                    byte[] waveform, int samplingRate) {
                // TODO Auto-generated method stub
                mVisualizerView.updateVisualizer(waveform);
            }

            @Override
            public void onFftDataCapture(Visualizer visualizer, byte[] fft,
                    int samplingRate) {
                // TODO Auto-generated method stub

            }
        }, Visualizer.getMaxCaptureRate() / 2, true, false);

    }

    @Override
    protected void onPause() {
        // TODO Auto-generated method stub
        super.onPause();
        if (isFinishing() && mMediaPlayer != null) {
            mVisualizer.release();
            mMediaPlayer.release();
            mEqualizer.release();
            mMediaPlayer = null;
        }
    }

    class VisualizerView extends View {

        private byte[] mBytes;
        private float[] mPoints;
        // 矩形区域
        private Rect mRect = new Rect();
        // 画笔
        private Paint mPaint = new Paint();

        // 初始化画笔
        private void init() {
            mBytes = null;
            mPaint.setStrokeWidth(1f);
            mPaint.setAntiAlias(true);
            mPaint.setColor(Color.BLUE);
        }

        public VisualizerView(Context context) {
            super(context);
            init();
        }

        public void updateVisualizer(byte[] mbyte) {
            mBytes = mbyte;
            invalidate();
        }

        @Override
        protected void onDraw(Canvas canvas) {
            // TODO Auto-generated method stub
            super.onDraw(canvas);

            if (mBytes == null) {
                return;
            }
            if (mPoints == null || mPoints.length < mBytes.length * 4) {
                mPoints = new float[mBytes.length * 4];
            }

            mRect.set(0, 0, getWidth(), getHeight());

            for (int i = 0; i < mBytes.length - 1; i++) {
                mPoints[i * 4] = mRect.width() * i / (mBytes.length - 1);
                mPoints[i * 4 + 1] = mRect.height() / 2
                        + ((byte) (mBytes[i] + 128)) * (mRect.height() / 2)
                        / 128;
                mPoints[i * 4 + 2] = mRect.width() * (i + 1)
                        / (mBytes.length - 1);
                mPoints[i * 4 + 3] = mRect.height() / 2
                        + ((byte) (mBytes[i + 1] + 128)) * (mRect.height() / 2)
                        / 128;
            }

            canvas.drawLines(mPoints, mPaint);

        }
    }
}
时间: 2024-10-13 15:37:01

android 实现跳动频谱 DEMO的相关文章

Android FragmentStatePageAdapter的使用Demo

上一篇写过FragmentPagerAdapter,这篇来介绍FragmentStatePagerAdapter,那么两者之间有何区别呢: FragmentPagerAdapter更多的用于少量界面的ViewPager,比如Tab.划过的fragment会保存在内存中,尽管已经划过.而FragmentStatePagerAdapter和ListView有点类似,会保存当前界面,以及下一个界面和上一个界面(如果有),最多保存3个,其他会被销毁掉. 如果想要更详细的了解,可以查看官网API,下面给出

Android SQLite最简单demo实现(增删查改)

本来不太想写这篇博客的,但是看到网上的关于android数据库操作的博文都讲得很详细,对于像我这样的新手入门了解SQLite的基本操作有一定难度,所以我参考了网上的一些博客文章,并自己亲自摸索了一遍,希望写出这么一篇博文来记录SQLite的最基本操作,同时也希望能够对android的新手们有些帮助. 参考博客:http://www.20864.com/201247/274.html 这里只是一个示范性的demo,并没实现什么具体功能,只实现了对数据库的增删查改操作. 以下是实现demo的步骤:

Android之ViewPager循环Demo

ViewPager是谷歌官方提供的兼容低版本安卓设备的软件包,里面包含了只有在安卓3.0以上可以使用的api.Viewpager现在也算是标配了,如果一个App没有用到ViewPager感觉还是比较罕见的,导航和页面菜单常用的功能,ViewPager与LisstView类似,ListView经常会用到BaseAdapter,ViewPager则继承的是PagerAdapter,关于简单的使用可以去官网可以http://developer.android.com/reference/android

android语音朗读功能demo实现

简单的文本语音朗读功能实现 实现这个功能主要用一个类,是TextToSpeech,废话不都少,直接上代码.总的来说效果一般,短语的停顿节奏不是很好. 界面很简单,一个Button ,一个EditView,就不贴代码了 public class ActivityResumptionArticle extends BaseActivity{    private TextToSpeech mSpeech = null;   private Button btn = null;   private E

Android studio百度地图demo出现230错误,key校验失败

转自daoxiaomianzi原文 Android studio 百度地图demo出现230错误,key校验失败 使用AndroidStudio导入Baidu地图的as版的demo,引入后,发现没有key,于是到http://lbsyun.baidu.com/apiconsole/key,创建应用,申请key,但是把sha1和报名都输入后,将key复制到manifest.xml里,部署到手机上,提示: 验证出错,错误码:230,请AndroidManifest.xml文件中检查 kye 设置.

Android蓝牙自动配对Demo,亲测好使!!!

蓝牙自动配对,即搜索到其它蓝牙设备之后直接进行配对,不需要弹出配对确认框或者密钥输入框. 转载请注明出处http://blog.csdn.net/qq_25827845/article/details/52400782 经过最近一段时间得研究,针对网上给出的案例.总结了一个亲测好使的Demo. 说明如下: 1.本Demo用来连接蓝牙设备HC-05,如果你要连接其他蓝牙设备,注意修改相关名字以及修改设备初试pin值. 2.将Demo安装在Android手机上,点击按钮,可以实现与目标蓝牙设备的自动

Android之SlideMenu实例Demo

年末加班基本上一周都没什么时候回家写代码,回到家就想睡觉,周末难得有时间写个博客,上次写了一篇关于SlideMenu开源项目的导入问题,这次主要讲讲使用的问题,SlideMenu应用的广泛程度就不用说了,基本上是App的标配,关于SlideMenu的各种使用方法有很多,网上各种Demo也很多,想来想去还是按照自己本身的实战方式去写写吧,走过的坑希望大家基本上不会遇到,开始正题: 基础布局 写布局文件之前先看下最终的效果图,昨天红色就是滑动出现的区域,右边的图片由左边的事件触发: activity

Android传感器Check小Demo

昨晚写了个关于Sensor的很简单的Demo,就是Check一下手机或者平板有没有所检测的传感器.由于今天一直在忙,现在才总结一下. 先看下运行截图: 三星Note 3: 三星GT-N8000: 下面是代码: package com.example.sensorcheck; import android.app.Activity; import android.content.Context; import android.hardware.Sensor; import android.hard

Android接入支付宝支付Demo

进入app支付文档有两种方式,一种是直接在下面的开放业务里 还有一种是通过上面的导航栏文档中心,然后滚动到业务接入那一栏,可以看到移动支付 当然也可以直接打开这个地址,文档还是挺多,可以关注我勾选的这几项 首先这里我也要说明的是个人是不能申请的,只能是企业,所以我demo里面的用的一些资料也是demo里面的 这里是交互流程的官方文档,需要详细的可以点进去看看 运行Demo 我们来到官方demo的下载地址 可以看到有两个,选择你需要的就行了,下载解压完直接导入eclipse并配置一些参数运行就可以