欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

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

程序员文章站 2023-12-04 11:53:58
android 调用自带的录制音频程序 android中有自带的音频录制程序,我们可以通过指定一个action mediastore.audio.media.record_...
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的源码,这样有助与你对音频的理解。
先看一下效果图
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即可!!