android音乐柱状频谱实现
from: http://blog.csdn.net/topgun38/article/details/7663849
原文地址:http://blog.csdn.net/caryee89/article/details/6935237
注意android2.3以后才可用,主要用到这个类Visualizer,这个源码其实是apiDemos中一个例子,但例子中实现的是两种中的波形显示,而不是频谱显示,
原文博主实现了另一种频谱显示,并分享出来,精神可嘉。我做了些修改,使稍微好看了些,继续分享。
官方文档解释:
public int getFft (byte[] fft)
Returns a frequency capture of currently playing audio content.
This method must be called when the Visualizer is enabled.
The capture is an 8-bit magnitude FFT, the frequency range covered being 0 (DC) to half of the sampling rate returned by getSamplingRate()
. The capture returns the real and imaginary parts of a number of frequency points equal to half of the capture size plus one.
Note: only the real part is returned for the first point (DC) and the last point (sampling frequency / 2).
The layout in the returned byte array is as follows:
- n is the capture size returned by getCaptureSize()
- Rfk, Ifk are respectively the real and imaginary parts of the kth frequency component
- If Fs is the sampling frequency retuned by getSamplingRate() the kth frequency is: (k*Fs)/(n/2)
Index | 0 | 1 | 2 | 3 | 4 | 5 | ... | n - 2 | n - 1 |
Data | Rf0 | Rf(n/2) | Rf1 | If1 | Rf2 | If2 | ... | Rf(n-1)/2 | If(n-1)/2 |
Parameters
fft | array of bytes where the FFT should be returned |
---|
Returns
SUCCESS
in case of success,ERROR_NO_MEMORY
,ERROR_INVALID_OPERATION
orERROR_DEAD_OBJECT
in case of failure.
Throws
IllegalStateException |
---|
实部和虚部的平方和就是振幅的平方,因为是byte类型,所以最大值是127。
对原文的代码做了一些修改,使更好看一些,代码中用到的歌曲谁要用到,自己重新放一首就行,代码如下:
- /*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- package com.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.audiofx.Equalizer;
- import android.media.audiofx.Visualizer;
- import android.os.Bundle;
- import android.util.Log;
- import android.view.Gravity;
- import android.view.View;
- import android.view.ViewGroup;
- import android.view.WindowManager;
- import android.widget.LinearLayout;
- import android.widget.SeekBar;
- import android.widget.TextView;
- public class AudioFxActivity extends Activity
- {
- private static final String TAG = "AudioFxActivity";
- private static final float VISUALIZER_HEIGHT_DIP = 160f;
- private MediaPlayer mMediaPlayer;
- private Visualizer mVisualizer;
- private Equalizer mEqualizer;
- private LinearLayout mLinearLayout;
- private VisualizerView mVisualizerView;
- private TextView mStatusTextView;
- private TextView mInfoView;
- @Override
- public void onCreate(Bundle icicle)
- {
- super.onCreate(icicle);
- mStatusTextView = new TextView(this);
- mLinearLayout = new LinearLayout(this);
- mLinearLayout.setOrientation(LinearLayout.VERTICAL);
- mLinearLayout.addView(mStatusTextView);
- setContentView(mLinearLayout);
- // Create the MediaPlayer
- mMediaPlayer = MediaPlayer.create(this, R.raw.my_life);
- Log.d(TAG,
- "MediaPlayer audio session ID: "
- + mMediaPlayer.getAudioSessionId());
- setupVisualizerFxAndUI();
- setupEqualizerFxAndUI();
- // Make sure the visualizer is enabled only when you actually want to
- // receive data, and
- // when it makes sense to receive data.
- mVisualizer.setEnabled(true);
- // When the stream ends, we don't need to collect any more data. We
- // don't do this in
- // setupVisualizerFxAndUI because we likely want to have more,
- // non-Visualizer related code
- // in this callback.
- mMediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener()
- {
- public void onCompletion(MediaPlayer mediaPlayer)
- {
- mVisualizer.setEnabled(false);
- getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
- setVolumeControlStream(AudioManager.STREAM_SYSTEM);
- mStatusTextView.setText("音乐播放完毕");
- }
- });
- getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
- setVolumeControlStream(AudioManager.STREAM_MUSIC);
- mMediaPlayer.start();
- mStatusTextView.setText("播放音乐中....");
- }
- private void setupEqualizerFxAndUI()
- {
- // Create the Equalizer object (an AudioEffect subclass) and attach it
- // to our media player,
- // with a default priority (0).
- mEqualizer = new Equalizer(0, mMediaPlayer.getAudioSessionId());
- mEqualizer.setEnabled(true);
- TextView eqTextView = new TextView(this);
- eqTextView.setText("均衡器:");
- mLinearLayout.addView(eqTextView);
- short bands = mEqualizer.getNumberOfBands();
- final short minEQLevel = mEqualizer.getBandLevelRange()[0];
- final short maxEQLevel = 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");
- mLinearLayout.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((minEQLevel / 100) + " dB");
- TextView maxDbTextView = new TextView(this);
- maxDbTextView.setLayoutParams(new ViewGroup.LayoutParams(
- ViewGroup.LayoutParams.WRAP_CONTENT,
- ViewGroup.LayoutParams.WRAP_CONTENT));
- maxDbTextView.setText((maxEQLevel / 100) + " dB");
- LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(
- ViewGroup.LayoutParams.FILL_PARENT,
- ViewGroup.LayoutParams.WRAP_CONTENT);
- layoutParams.weight = 1;
- SeekBar bar = new SeekBar(this);
- bar.setLayoutParams(layoutParams);
- bar.setMax(maxEQLevel - minEQLevel);
- bar.setProgress(mEqualizer.getBandLevel(band));
- bar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener()
- {
- public void onProgressChanged(SeekBar seekBar, int progress,
- boolean fromUser)
- {
- mEqualizer.setBandLevel(band, (short) (progress + minEQLevel));
- }
- public void onStartTrackingTouch(SeekBar seekBar)
- {
- }
- public void onStopTrackingTouch(SeekBar seekBar)
- {
- }
- });
- row.addView(minDbTextView);
- row.addView(bar);
- row.addView(maxDbTextView);
- mLinearLayout.addView(row);
- }
- }
- private void setupVisualizerFxAndUI()
- {
- mVisualizerView = new VisualizerView(this);
- mVisualizerView.setLayoutParams(new ViewGroup.LayoutParams(
- ViewGroup.LayoutParams.FILL_PARENT,
- (int) (VISUALIZER_HEIGHT_DIP * getResources()
- .getDisplayMetrics().density)));
- mLinearLayout.addView(mVisualizerView);
- mInfoView = new TextView(this);
- String infoStr = "";
- int[] csr = Visualizer.getCaptureSizeRange();
- if(csr != null)
- {
- String csrStr = "CaptureSizeRange: ";
- for(int i = 0; i < csr.length; i ++)
- {
- csrStr += csr[i];
- csrStr +=" ";
- }
- infoStr += csrStr;
- }
- final int maxCR = Visualizer.getMaxCaptureRate();
- infoStr = infoStr + "\nMaxCaptureRate: " + maxCR;
- mInfoView.setText(infoStr);
- mLinearLayout.addView(mInfoView);
- mVisualizer = new Visualizer(mMediaPlayer.getAudioSessionId());
- mVisualizer.setCaptureSize(256);
- mVisualizer.setDataCaptureListener(
- new Visualizer.OnDataCaptureListener()
- {
- public void onWaveFormDataCapture(Visualizer visualizer,
- byte[] bytes, int samplingRate)
- {
- mVisualizerView.updateVisualizer(bytes);
- }
- public void onFftDataCapture(Visualizer visualizer,
- byte[] fft, int samplingRate)
- {
- mVisualizerView.updateVisualizer(fft);
- }
- }, maxCR / 2, false, true);
- }
- @Override
- protected void onPause()
- {
- super.onPause();
- if (isFinishing() && mMediaPlayer != null)
- {
- mVisualizer.release();
- mEqualizer.release();
- mMediaPlayer.release();
- mMediaPlayer = null;
- }
- }
- /**
- * A simple class that draws waveform data received from a
- * {@link Visualizer.OnDataCaptureListener#onWaveFormDataCapture }
- */
- class VisualizerView extends View
- {
- private byte[] mBytes;
- private float[] mPoints;
- private Rect mRect = new Rect();
- private Paint mForePaint = new Paint();
- private int mSpectrumNum = 48;
- private boolean mFirst = true;
- public VisualizerView(Context context)
- {
- super(context);
- init();
- }
- private void init()
- {
- mBytes = null;
- mForePaint.setStrokeWidth(8f);
- mForePaint.setAntiAlias(true);
- mForePaint.setColor(Color.rgb(0, 128, 255));
- }
- public void updateVisualizer(byte[] fft)
- {
- if(mFirst )
- {
- mInfoView.setText(mInfoView.getText().toString() + "\nCaptureSize: " + fft.length);
- mFirst = false;
- }
- byte[] model = new byte[fft.length / 2 + 1];
- model[0] = (byte) Math.abs(fft[0]);
- for (int i = 2, j = 1; j < mSpectrumNum;)
- {
- model[j] = (byte) Math.hypot(fft[i], fft[i + 1]);
- i += 2;
- j++;
- }
- mBytes = model;
- invalidate();
- }
- @Override
- protected void onDraw(Canvas canvas)
- {
- 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;
- // }
- //绘制频谱
- final int baseX = mRect.width()/mSpectrumNum;
- final int height = mRect.height();
- for (int i = 0; i < mSpectrumNum ; i++)
- {
- if (mBytes[i] < 0)
- {
- mBytes[i] = 127;
- }
- final int xi = baseX*i + baseX/2;
- mPoints[i * 4] = xi;
- mPoints[i * 4 + 1] = height;
- mPoints[i * 4 + 2] = xi;
- mPoints[i * 4 + 3] = height - mBytes[i];
- }
- canvas.drawLines(mPoints, mForePaint);
- }
- }
- }
运行效果如下:
android音乐柱状频谱实现的更多相关文章
- Android 自定义View - 柱状波形图 wave view
前言 柱状波形图是一种常见的图形.一个个柱子按顺序排列,构成一个波形图. 柱子的高度由输入数据决定.如果输入的是音频的音量,则可得到一个声波图. 在一些音频软件中,我们也可以左右拖动声波,来改变音频的 ...
- Android音乐播放器源码(歌词.均衡器.收藏.qq5.0菜单.通知)
一款Android音乐播放器源码,基本功能都实现了 qq5.0菜单(歌词.均衡器.收藏.qq5.0菜单.通知) 只有向右滑动出现,菜单键和指定按钮都还没有添加. 源码下载:http://code.66 ...
- 一款非常简单的android音乐播放器源码分享给大家
一款非常简单的android音乐播放器源码分享给大家,该应用虽然很小,大家常用的播放器功能基本实现了,可能有点还不够完善,大家也可以自己完善一下,源码在源码天堂那里已经有了,大家可以到那里下载学习吧. ...
- Android无限级树状结构
通过对ListView简单的扩展.再封装,即可实现无限层级的树控件TreeView. package cn.asiontang.nleveltreelistview; import android.a ...
- 用canvas 绘制的饼状统计图、柱状统计图、折线统计图
canvas 绘制的饼状统计图 canvas 绘制的柱状统计图 canvas 绘制的折线统计图
- android音乐播放器开发教程
android音乐播放器开发教程 Android扫描sd卡和系统文件 Android 关于录音文件的编解码 实现米聊 微信一类的录音上传的功能 android操作sdcard中的多媒体文件——音乐列表 ...
- iOS 使用Charts框架 折线,柱状,K线,饼状,雷达全攻略
我是前言: 大约几个月前我在某平台写了一篇文章, 文中简单地介绍了Charts两种图表的样式的使用, 不过有种意犹未尽的感觉, 利用周末的空闲时间再次看了看, 有了新的收获, 今天发出来,分享给大家, ...
- 用Jfree实现条形柱状图表,java代码实现
用Jfree实现条形柱状图表,java代码实现.可经经常使用于报表的制作,代码自己主动生成后能够自由查看.能够自由配置图表的各个属性,用来达到自己的要求和目的 package test1; impor ...
- 用echartsjs 实现动态绘制折线、柱状等图形,并实现多图联动效果
echarts对于大数据处理后绘制折线图,柱形图等等的效果和速度都很好.下面我们介绍 怎么把封装的数据列表解析出来,动态绘图,并且实现鼠标联动效果引入js文件: <script type=&qu ...
随机推荐
- java 汉字转拼音
先决条件: pinyin4j.jar(Pinyin4j是一个流行的Java库,支持中文字符和拼音之间的转换.拼音输出格式可以定制.) 下载地址:http://pan.baidu.com/share/l ...
- XML读写文件辅助类
/// <summary> /// 历史下载记录xml文件操作 /// </summary> public class XMLHelper { private string x ...
- Hibernate学习之缓存机制
转自:http://www.cnblogs.com/xiaoluo501395377/p/3377604.html 一.N+1问题 首先我们来探讨一下N+1的问题,我们先通过一个例子来看一下,什么是N ...
- Cloudera Manager Service Monitor 定期挂掉问题排查
显示:查询 Service Monitor 时发生内部错误(Error sending messages to firehose: mgmt-SERVICEMONITOR-) 1.初步排查出是smon ...
- @Transactional失效的问题
spring事物配置一般没有问题, 优先检查mysql的引擎是否是innodb, 是的话检查包的扫描是否有问题. 我就是因为包的扫描导致@Transactional失效. 具体情况如下, 在sprin ...
- 关于Python的self指向性
Python的self是指向类的实例化对像,而不是类本身,每次调用类的实例化即self指向此实例化对像,如下代码: class Person: def __init__(self,name): sel ...
- cocos2d-x Android环境搭建
1.Java虚拟机.分32位和64位.64位: jdk-8u11-windows-x64-8.0.11.12.1406275777 环境变量配置,我的电脑右击->属性->高级系统设置-&g ...
- 射频识别技术漫谈(16)——Mifare UltraLight
Mifare UltraLight又称为MF0,从UltraLight(超轻的)这个名字就可以看出来,它是一个低成本.小容量的卡片.低成本,是指它是目前市场中价格最低的遵守ISO14443A协议的芯片 ...
- MSSQL SERVER 2008 R2 无法连接到数据库,用户sa登录失败,错误:18456
原因:勾选了强制实施密码策略,但是设置的密码很简单依然可以,比如:123456 这是为什么?原来,这个功能要用到NetValidatePasswordPolicy() API这个函数. (该功能只有在 ...
- android天气查询(一)websevice之ksoap2软件包的使用
对于用到天气信息,首先我想: 第一:数据不可能是我测得的,必须是网上的信息. 第二:网上的信息分为好多种,具体哪种比较好一点,这里我总结了两种. 第三:数据JSON怎么解析. 第四:如何提出数据与显示 ...