android pcm频谱_Android音频开发(7):音乐可视化-FFT频谱图
Android 音频开发 目录
一、演示
image
二、实现
实现流程:
使用MediaPlayer播放传入的音乐,并拿到mediaPlayerId
使用Visualizer类拿到拿到MediaPlayer播放中的音频数据(wave/fft)
将数据用自定义控件展现出来
三、准备工作
使用Visualizer需要录音的动态权限, 如果播放sd卡音频需要STORAGE权限
private static final String[] PERMISSIONS = new String[]{
Manifest.permission.RECORD_AUDIO,
Manifest.permission.MODIFY_AUDIO_SETTINGS
};
ActivityCompat.requestPermissions(MainActivity.this, PERMISSIONS, 1);
四、开始播放
private MediaPlayer.OnPreparedListener preparedListener = new
/**
* 播放音频
*
* @param raw 资源文件id
*/
private void doPlay(final int raw) {
try {
mediaPlayer = MediaPlayer.create(MyApp.getInstance(), raw);
if (mediaPlayer == null) {
Logger.e(TAG, "mediaPlayer is null");
return;
}
mediaPlayer.setOnErrorListener(errorListener);
mediaPlayer.setOnPreparedListener(preparedListener);
} catch (Exception e) {
Logger.e(e, TAG, e.getMessage());
}
}
/**
* 获取MediaPlayerId
* 可视化类Visualizer需要此参数
* @return MediaPlayerId
*/
public int getMediaPlayerId() {
return mediaPlayer.getAudioSessionId();
}
五、使用可视化类Visualizer获取当前音频数据
Visualizer 有两个比较重要的参数
设置可视化数据的数据大小 范围[Visualizer.getCaptureSizeRange()[0]~Visualizer.getCaptureSizeRange()[1]]
社会可视化数据的采集频率 范围[0~Visualizer.getMaxCaptureRate()]
OnDataCaptureListener 有2个回调,一个用于显示FFT数据,展示不同频率的振幅,另一个用于显示声音的波形图
private Visualizer.OnDataCaptureListener dataCaptureListener = new Visualizer.OnDataCaptureListener() {
@Override
public void onWaveFormDataCapture(Visualizer visualizer, final byte[] waveform, int samplingRate) {
audioView.post(new Runnable() {
@Override
public void run() {
audioView.setWaveData(waveform);
}
});
}
@Override
public void onFftDataCapture(Visualizer visualizer, final byte[] fft, int samplingRate) {
audioView2.post(new Runnable() {
@Override
public void run() {
audioView2.setWaveData(fft);
}
});
}
};
private void initVisualizer() {
try {
int mediaPlayerId = mediaPlayer.getMediaPlayerId();
if (visualizer != null) {
visualizer.release();
}
visualizer = new Visualizer(mediaPlayerId);
/**
*可视化数据的大小: getCaptureSizeRange()[0]为最小值,getCaptureSizeRange()[1]为最大值
*/
int captureSize = Visualizer.getCaptureSizeRange()[1];
int captureRate = Visualizer.getMaxCaptureRate() * 3 / 4;
visualizer.setCaptureSize(captureSize);
visualizer.setDataCaptureListener(dataCaptureListener, captureRate, true, true);
visualizer.setScalingMode(Visualizer.SCALING_MODE_NORMALIZED);
visualizer.setEnabled(true);
} catch (Exception e) {
Logger.e(TAG, "请检查录音权限");
}
}
波形数据和傅里叶数据的关系请看面这张图:
image
六、编写自定义控件,展示数据
处理数据: visualizer 回调中的数据中是存在负数的,需要转换一下,用于显示
当byte 为 -128时Math.abs(fft[i]) 计算出来的值会越界,需要手动处理一下
byte 的范围: -128~127
/**
* 预处理数据
*
* @return
*/
private static byte[] readyData(byte[] fft) {
byte[] newData = new byte[LUMP_COUNT];
byte abs;
for (int i = 0; i < LUMP_COUNT; i++) {
abs = (byte) Math.abs(fft[i]);
//描述:Math.abs -128时越界
newData[i] = abs < 0 ? 127 : abs;
}
return newData;
}
紧接着就是根据数据去绘制图形
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
wavePath.reset();
for (int i = 0; i < LUMP_COUNT; i++) {
if (waveData == null) {
canvas.drawRect((LUMP_WIDTH + LUMP_SPACE) * i,
LUMP_MAX_HEIGHT - LUMP_MIN_HEIGHT,
(LUMP_WIDTH + LUMP_SPACE) * i + LUMP_WIDTH,
LUMP_MAX_HEIGHT,
lumpPaint);
continue;
}
switch (upShowStyle) {
case STYLE_HOLLOW_LUMP:
drawLump(canvas, i, false);
break;
case STYLE_WAVE:
drawWave(canvas, i, false);
break;
default:
break;
}
switch (downShowStyle) {
case STYLE_HOLLOW_LUMP:
drawLump(canvas, i, true);
break;
case STYLE_WAVE:
drawWave(canvas, i, true);
break;
default:
break;
}
}
}
/**
* 绘制矩形条
*/
private void drawLump(Canvas canvas, int i, boolean reversal) {
int minus = reversal ? -1 : 1;
if (waveData[i] < 0) {
Logger.w("waveData", "waveData[i] < 0 data: %s", waveData[i]);
}
float top = (LUMP_MAX_HEIGHT - (LUMP_MIN_HEIGHT + waveData[i] * SCALE) * minus);
canvas.drawRect(LUMP_SIZE * i,
top,
LUMP_SIZE * i + LUMP_WIDTH,
LUMP_MAX_HEIGHT,
lumpPaint);
}
/**
* 绘制曲线
* 这里使用贝塞尔曲线来绘制
*/
private void drawWave(Canvas canvas, int i, boolean reversal) {
if (pointList == null || pointList.size() < 2) {
return;
}
float ratio = SCALE * (reversal ? -1 : 1);
if (i < pointList.size() - 2) {
Point point = pointList.get(i);
Point nextPoint = pointList.get(i + 1);
int midX = (point.x + nextPoint.x) >> 1;
if (i == 0) {
wavePath.moveTo(point.x, LUMP_MAX_HEIGHT - point.y * ratio);
}
wavePath.cubicTo(midX, LUMP_MAX_HEIGHT - point.y * ratio,
midX, LUMP_MAX_HEIGHT - nextPoint.y * ratio,
nextPoint.x, LUMP_MAX_HEIGHT - nextPoint.y * ratio);
canvas.drawPath(wavePath, lumpPaint);
}
}
android pcm频谱_Android音频开发(7):音乐可视化-FFT频谱图相关推荐
- Android音频开发(7):音乐可视化-FFT频谱图
Android 音频开发 目录 Android音频开发(1):音频相关知识 Android音频开发(2):使用AudioRecord录制pcm格式音频 Android音频开发(3):使用AudioRe ...
- android 音乐 简书,Android音频开发(7):音乐可视化-FFT频谱图
Android 音频开发 目录 一.演示 image 二.实现 实现流程: 使用MediaPlayer播放传入的音乐,并拿到mediaPlayerId 使用Visualizer类拿到拿到MediaPl ...
- android pcm 音量_Android中实时获取音量分贝值详解
基础知识 度量声音强度,大家最熟悉的单位就是分贝(decibel,缩写为dB).这是一个无纲量的相对单位,计算公式如下: 分子是测量值的声压,分母是参考值的声压(20微帕,人类所能听到的最小声压).因 ...
- android pcm频谱_Android音频可视化
本文作者:熊鋆洋 (网易云音乐大前端团队) 前言 音频可视化,顾名思义就是将声音以视觉的方式呈现出来.如何将音频信号绘制出来?如何将声音的变化在视觉上清晰的表现出来,让视觉和听觉上的感受一致?这些在 ...
- android pcm文件大小_Android 音视频开发(二):使用 AudioRecord 采集音频PCM并保存到文件...
一.AudioRecord API详解 AudioRecord是Android系统提供的用于实现录音的功能类. 要想了解这个类的具体的说明和用法,我们可以去看一下官方的文档: AndioRecord类 ...
- android 自定义频谱,android – 如何从实时音频开发频谱分析仪?
我正在开发一个应用程序,实时从麦克风获取源音频,没有文件存储.基本上,我使用: mRecorder = new MediaRecorder(); mRecorder.setAudioSource(Me ...
- android开发歌词滑动效果_Android应用开发--MP3音乐播放器滚动歌词实现
[android]代码库2013年6月2日 简.美音乐播放器开发记录 -----主题 这篇博客的主题是:"滚动歌词的实现" 要的效果如下: ----实现过程 1. 建立歌词内容实体 ...
- android pcm文件大小_Android中的PCM设备
Android上的应用一般都是通过AudioTrack类来播放音频,通过AudioRecord类来录制音频.AudioTrack类和AudioRecord类是Android Frameworks封装提 ...
- android cmake 打印_Android NDK 开发:CMake 使用
1. 前言 当在做 Android NDK 开发时,如果不熟悉用 CMake 来构建,读不懂 CMakeLists.txt 的配置脚本,很容易就会踩坑,遇到编译失败,一个很小的配置问题都会浪费很多时间 ...
最新文章
- [05]EXTJS4.0的读写器reader,writer
- 一篇叫做决心书的文章
- openapi开放平台架构_适用于所有人的MicroProfile OpenAPI
- 机器视觉与深度神经网络—洗去浮华,一窥珠玑
- linux xia 安装程序,linux更新或安装libzip
- Imation亏损额急剧增长 CEO仍表示“成功”
- 机器学习实战的P264中代码对应的公式推导
- 查看linux的用户
- Workflow WF Reference Links for 2009-03-20
- 查看mysql错误日志定位mysql错误
- (转)Nutz | Nutz项目整合Spring实战
- braft的LogEntry日志记录存储LogStorage
- 计算机专业的大专大学规划,大学生计算机专业职业规划个人简历
- 香港十大外汇交易平台排名(2021最新版)
- 走进波分 -- 03.光纤传输系统关键参数
- 写给那些让我糊里糊涂的HTTP、TCP、UDP、Socket
- 华三交换机基本配置命令
- 笔记本电脑屏幕亮度无法调节
- 深度学习研究生常用网站||图像处理||医学影像||使用评价||汇总
- Web前端开发技术课程大作业——南京旅游景点介绍网页代码html+css+javascript