Android音频可视化开发案例说明

Android 调用自带的录制音频程序

Android中有自带的音频录制程序,我们可以通过指定一个Action MediaStore.Audio.Media.RECORD_SOUND_ACTION的Intent来

启动它就可以了。然后在onActivityResult()方法中,获取Intent的Data,就是录制的音频对应的URI。

java代码:

复制代码 代码如下:

package eoe.demo;

import android.app.Activity;

import android.content.Intent;

import android.net.Uri;

import android.os.Bundle;

import android.provider.MediaStore;

import android.view.View;

import android.widget.Toast;

/**

* 被实例演示如何调用Android自带的应用来完成Audio的录入

* 其实很简单,我们需要指定一个MediaStore.Audio.Media.RECORD_SOUND_ACTION的Action来启动就可以

* 返回的Data数据就是我们录制的音频的URI了

*

* 通过上面这种方式,灵活性不够高,我们可以利用MediaRecorder类来实现自己的音频录制程序

* MediaRecorder既可以用来录制音频,也可以用来录制视频

* 创建了一个MediaRecorder实例后,需要调用setAudioSource和setAudioEncoder来初始化

* 通常情况下,在准备录制前,我们还需要调用setOutputFormat()方法来决定使用的音频格式,同时调用

* setOutputFile()来指定存放录制内容的文件

*

* 这几个方法的调用顺序是:setAudioSource,setOutputFormat,setAudioEncoder,setOutputFile

*

*

*

* @author Administrator

*

*/

public class AudioRecordDemo extends Activity {

public void onCreate(Bundle savedInstanceState){

super.onCreate(savedInstanceState);

setContentView(R.layout.audio_record);

}

public void onActivityResult(int requestCode, int resultCode, Intent data){

//super.onActivityResult(requestCode, resultCode, data);

//这里我们就可以获取到刚刚录制的音频的Uri,可以进行播放等操作,这里显示返回的Uri

if(resultCode == RESULT_OK){

Uri audioPath = data.getData();

Toast.makeText(this, audioPath.toString(), Toast.LENGTH_LONG).show();

}

}

public void onClick(View v){

int id = v.getId();

switch(id){

case R.id.btn1: //调用Android自带的音频录制应用

Intent intent = new Intent(MediaStore.Audio.Media.RECORD_SOUND_ACTION);

startActivityForResult(intent, 0);

break;

case R.id.btn2:

//通过MediaRecorder类来实现自己的音频录制程序

Intent intent2 = new Intent();

intent2.setClass(this, MyAudioRecord.class);

startActivityForResult(intent2, 1);

break;

case R.id.btn3:

//通过AudioRecord类实现自己的音频录制程序

Intent intent3 = new Intent();

intent3.setClass(this, MyAudioRecord2.class);

startActivityForResult(intent3, 2);

break;

}

}

}

Android 音频的介绍

最近移植Android,当Android能够在设备上面运行之后,首先想到的是让音频设备跑起来。“没有声音,再好的戏也出不来”。本文简单介绍一下Android音频适配层。

这个世界音频设备千变万化,Android也不可能为每种设备都提供支持。Android定义了一个框架,这个框架来适配底层的音频设备。该适配层的定义位于:

Java代码:

复制代码 代码如下:

hardware/libhardware_legacy/include/hardware_legacy/AudioHardwareInterface.h

要想视频底层的音频设备必须要继承该文件中定义的AudioStreamOut,AudioStreamIn,AudioHardwareInterface等类,并实现createAudioHardware函数。

下面我们看一下Android创建音频设备的代码,代码位于:

Java代码:

复制代码 代码如下:

frameworks/base/libs/audioflinger/AudioHardwareInterface.cpp

该文件有如下代码:

Java代码:

复制代码 代码如下:

AudioHardwareInterface* AudioHardwareInterface::create()

{

/*

* FIXME: This code needs to instantiate the correct audio device

* interface. For now - we use compile-time switches.

*/

AudioHardwareInterface* hw = 0;

char value[PROPERTY_VALUE_MAX];

#ifdef GENERIC_AUDIO

hw = new AudioHardwareGeneric();

#else

// 如果运行在仿真中——用这个模拟器

if (property_get("ro.kernel.qemu", value, 0)) {

LOGD("Running in emulation - using generic audio driver");

hw = new AudioHardwareGeneric();

}

else {

LOGV("Creating Vendor Specific AudioHardware");

hw = createAudioHardware();

}

#endif

if (hw->initCheck() != NO_ERROR) {

LOGW("Using stubbed audio hardware. No sound will be produced.");

delete hw;

hw = new AudioHardwareStub();

}

#ifdef WITH_A2DP

hw = new A2dpAudioInterface(hw);

#endif

#ifdef ENABLE_AUDIO_DUMP

recorded in the file.

LOGV("opening PCM dump interface");

hw = new AudioDumpInterface(hw); // replace interface

#endif

return hw;

}

从代码中我们可以看出如果定义了GENERIC_AUDIO的宏,则会创建AudioHardwareGeneric,如果是模拟器的话,AudioHardwareGeneric会不能初始化,进而创建AudioHardwareStub。这两个类都是Audio设备的适配层,是Android默认提供的。模拟器都是用AudioHardwareStub,不会有声音输出。设备都是用AudioHardwareGeneric,因为默认GENERIC_AUDIO是设置的。

一般我们只关心AudioHardwareGeneric实现,谁会去给模拟器去调试声音呢,反正我没这个闲心。首先说明一下这个音频适配层是Android自带的,可以保证你的音频设备正常运行,但是不能发挥设备的最佳性能。通过后面的描述你将会了解。AudioHardwareGeneric的定义位于:

Java代码:

复制代码 代码如下:

frameworks/base/libs/audioflinger/AudioHardwareGeneric.cpp

上面就是eoe给我们介绍音频用途,如果有什么不明白的就多看看android的源码,这样有助与你对音频的理解。

先看一下效果图:

 

复制代码 代码如下:

public class FFTActivity extends Activity implements OnClickListener{

private Button button;

private ImageView imageView;

private int frequency = 8000;

private int channelConfiguration = AudioFormat.CHANNEL_CONFIGURATION_MONO;

private int audioEncoding = AudioFormat.ENCODING_PCM_16BIT;

private RealDoubleFFT transformer;

private int blockSize = 256;

private boolean started = false;

private Canvas canvas;

private Paint paint;

private Bitmap bitmap;

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.fft);

button = (Button) findViewById(R.id.fft_button);

button.setOnClickListener(this);

imageView = (ImageView) findViewById(R.id.fft_imageView);

transformer = new RealDoubleFFT(blockSize);

bitmap = Bitmap.createBitmap(256, 100, Bitmap.Config.ARGB_8888);

canvas = new Canvas(bitmap);

paint = new Paint();

paint.setColor(Color.GREEN);

imageView.setImageBitmap(bitmap);

}

private class RecordAudio extends AsyncTask<Void, double[], Void> {

@Override

protected Void doInBackground(Void... params) {

int bufferSize = AudioRecord.getMinBufferSize(frequency,

channelConfiguration, audioEncoding);

AudioRecord audioRecord = new AudioRecord(

MediaRecorder.AudioSource.MIC, frequency,

channelConfiguration, audioEncoding, bufferSize);

short[] buffer = new short[blockSize];

double[] toTransform = new double[blockSize];

audioRecord.startRecording();

while (started) {

//将record的数据 读到buffer中,但是我认为叫做write可能会比较合适些。

int bufferResult = audioRecord.read(buffer, 0, blockSize);

for (int i = 0; i < bufferResult; i++) {

toTransform<i> = (double) buffer<i> / Short.MAX_VALUE;

}

transformer.ft(toTransform);

publishProgress(toTransform);

}

audioRecord.stop();

return null;

}

@Override

protected void onProgressUpdate(double[]... values) {

super.onProgressUpdate(values);

canvas.drawColor(Color.BLACK);

for (int i = 0; i < values[0].length; i++) {

int x=i;

int downy=(int)(100-(values[0]<i>)*10);

int upy=100;

canvas.drawLine(x, downy, x, upy, paint);

}

imageView.invalidate();

}

}

@Override

public void onClick(View v) {

started=true;

new RecordAudio().execute();

}

}

android音频可视化的原理是使用离散傅里叶变换,但是数学不好的同学不要担心,有开源的java离散傅里叶变换的代码!!直接到www.netlib.org/fftpack/jfftpack.tgz,直接将里面javasource目录拖动到(ca目录)src即可!!

时间: 2024-10-02 14:11:39

Android音频可视化开发案例说明的相关文章

Android音频可视化开发案例说明_Android

Android 调用自带的录制音频程序 Android中有自带的音频录制程序,我们可以通过指定一个Action MediaStore.Audio.Media.RECORD_SOUND_ACTION的Intent来 启动它就可以了.然后在onActivityResult()方法中,获取Intent的Data,就是录制的音频对应的URI. java代码: 复制代码 代码如下: package eoe.demo; import android.app.Activity; import android.

Android 音频技术开发总结

在文章开头,我们先来了解几个概念,这样有利于对后面内容的理解. 1.概念理解 采样率:即采样频率,百科的解释是,每秒从连续信号中提取并组成离散信号的采样个数,单位 赫兹(Hz).通俗的讲采样频率是指计算机每秒钟采集多少个声音样本,是描述声音文件的音质.音调,衡量声卡.声音文件的质量标准.好吧,感觉这样还是不太理解,那我们来看看下面的解释: 如图, 采样就是把模拟信号数字化的过程,不仅仅是音频需要采样,所有的模拟信号都需要通过采样转换为可以用 0101 来表示的数字信号,上图蓝色代表模拟音频信号,

《Android开发案例驱动教程》

<Android开发案例驱动教程>   作者:关东升,赵志荣Java或C++程序员转变成为Android程序员 采用案例驱动模式展开讲解知识点,即介绍案例->案例涉及技术->展开知识点->总结的方式 本书作者从事多年一线开发和培训,讲解知识点力求细致,深入浅出 目    录 前言 第1章  Android操作系统概述 1 1.1  Android历史介绍 1 1.2  Android架构 1 1.3  Android平台介绍 2 1.4  现有智能手机操作系统比较 4 第2章

《Android多媒体应用开发实战详解:图像、音频、视频、2D和3D》——2.1节简析Android安装文件

2.1 简析Android安装文件 Android多媒体应用开发实战详解:图像.音频.视频.2D和3D 当下载并安装Android后,会在其安装目录中看到一些安装文件.了解这些文件具体是干什么用的,对于我们后面的驱动开发知识学习十分有用,所以在本节的内容中将简要介绍这些安装文件的基本知识. 2.1.1 Android SDK目录结构 安装Android SDK后,其安装目录的具体结构如图2-1所示. temp:里面包含了一些常用的文件模板. tools:包含了一些通用的工具文件. usb_dri

《Android 平板电脑开发实战详解和典型案例》——1.2节开发环境的搭建

1.2 开发环境的搭建 Android 平板电脑开发实战详解和典型案例 本节开始进入Android的开发,首先介绍开发环境的搭建.开发环境的搭建分为3个步骤:SDK的安装与环境变量配置.Eclipse集成开发环境的搭建.模拟器的创建与使用,下面对其一一进行讲解. 1.2.1 Android SDK的安装与环境变量配置 Android SDK的安装与环境变量配置包括如下几个步骤. (1) 在Oracle的官方网站上,下载相应的JDK软件(网址为:http://www.oracle.com/tech

《Android 平板电脑开发实战详解和典型案例》——2.5节数字选择控件—— NumberPiker

2.5 数字选择控件-- NumberPiker Android 平板电脑开发实战详解和典型案例 上一节中,介绍了ActionBar的基本知识及简单案例,本节将介绍Android 3.0新增控件数字选择控件NumberPicker,主要内容包括其基本知识以及一个简单的案例. 2.5.1 数字选择控件基本知识 数字选择控件NumberPiker可以理解成由两个Button中夹着一个EditText组成,EditText用来显示数字,而两个Button按钮则控制EditText中数字的增减.数字选择

《Android 平板电脑开发实战详解和典型案例》——2.1节搜索框控件—— SearchView

2.1 搜索框控件-- SearchView Android 平板电脑开发实战详解和典型案例 本节将介绍Android 3.0新增控件--搜索框控件SearchView,主要内容包括搜索框控件SearchView的基本知识以及一个简单的案例. 提示 本书中的案例都是在540×960分辨率的真机上调试通过的,若执行本书中案例的设备分辨率不是540×960,可能会有显示不正常的情况.但大部分案例都是没有问题的,尤其是最后第14.第15.第16章的大案例都是自适应于各种屏幕分辨率的. 2.1.1 搜索

《Android 平板电脑开发实战详解和典型案例》——2.3节弹出菜单—— PopupMenu

2.3 弹出菜单-- PopupMenu Android 平板电脑开发实战详解和典型案例 上一节中我们介绍了Switch的基本知识及简单案例.本节将介绍Android 3.0新增控件弹出菜单PopupMenu,主要内容包括其基本知识以及一个简单的案例. 2.3.1 弹出菜单基本知识 弹出菜单PopupMenu 是一个下拉菜单控件,可增加多条下拉菜单以及给每条下拉菜单增加子菜单.可通过new PopupMenu(context, view)创建一个下拉菜单,view为单击的控件,点此view时显示

《Android 平板电脑开发实战详解和典型案例》——2.6节可展开列表—— ExpandableListView

2.6 可展开列表-- ExpandableListView Android 平板电脑开发实战详解和典型案例 上一节中介绍了NumberPicker的基本知识及简单案例,本节将介绍Android 2.0控件可扩展列表ExpandableListView,主要内容包括其基本知识以及一个简单的案例. 2.6.1 可展开列表基本知识 可展开列表ExpandableListView在主界面显示的效果就是下拉菜单.当单击可展开列表ExpandableListView时会弹出一个子菜单,当再单击时界面就会恢