首页 > 系统 > Android > 正文

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

2019-10-24 21:09:14
字体:
来源:转载
供稿:网友
最近移植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.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即可!!
 

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表