大家好,又见面了,我是你们的朋友全栈君。
源码下载地址:http://download.csdn.net/detail/songconglai/7312933
MainActivity.java :
1. 主类,播放方波(提供byteDate)和正弦波。
2. 提供三个按钮分别为 短方波(btnPlayFS)、长方波(btnPlayFL)、正弦波(btnPlayZ),其功能如下:
2.1. btnPlayFS /btnPlayFL 单击事件 :实例化WaveOutF(方波类),调用sendByteDate(byte[],length)方法 传送byteDate和有效长度,
如果已经实例化则直接调用sendByteDate方法;
2.2. btnPlayZ 单击事件 :实例化WaveOutZ(正弦波类),调用palyWaveZ()方法,播放正弦波;
2.3. btnStopZ 单击事件:调用WaveOutZ下的colseWaveZ()方法 ,停止正弦波的播放。
3. 实现onKeyDown构造方法:当用户点击返回按钮时注销已经打开的WaveOutF和WaveOutZ占用的资源,结束程序。
WaveOutF.java :
1.方波类,实现播放方波。
2. 实例化 该类时,构造AudioTrack对象, 设置 类型:系统声音,采样率:44100,声道:单声道(右),
采样精度:16bit,缓冲区大小:4096,模式:流媒体。
3.方法:
3.1. sendByteDate(byte[] byteDate,int len)将byteDate通过getShortDate()方法转换为音频源,
开一个线程(audioTrackThread)播放。
3.2. getShortDate()先 将byteDate通过getstrBinary(byte[] date, int lenght)方法转为转为2进制字符串,
定义一个short[58*字符串长度]数组 ,再将字符串通过String.charAt(int i)检索出“1”则连续赋58个32767给数组,
否则连续赋58个-32768给数组,返回数组(音频数据)。
3.3. getstrBinary(byte[] date, int lenght) 将字节编码转为2进制字符串并补0,返回2进制字符串。
3.4. playWaveF(short[] m_bitDateF) 写入音频数据给音频硬件进行播放,该方法是阻塞的。
3.5. closeAudioTrack() 停止播放音频数据。
4. 线程:AudioTrackThread 调用playWaveF方法。
WaveOutZ.java :
1. 正弦波类,实现播放正弦波。
2. 实例化 该类时,构造AudioTrack对象 ,设置 类型:系统声音,采样率:44100,声道:单声道(左),
采样精度:16bit,缓冲区大小:2*4096,模式:流媒体。
3.方法:
3.1. palyWaveZ() 开一个线程audioTrackZThread 播放正弦波;
3.2. colseWaveZ() 通过标志位isRunning 关闭线程
4.线程:AudioTrackZThread 定义一个short[44100]数组 通过算法:32767*Sin((2*3.1415926*8250.0/44100.0)*i)给数组赋值,
写入音频数据到音频硬件进行播放
package scl.wavedome2;
import scl.waveout.WaveOutF;
import scl.waveout.WaveOutZ;
import android.app.Activity;
import android.os.Bundle;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
public class MainActivity extends Activity {
private Button btnPlayFS;// 方波按钮
private Button btnPlayFL;
private Button btnStopZ;// 停止正弦波
private Button btnPlayZ;// 正弦波按钮
private WaveOutF woF;// 方波类
private WaveOutZ woZ;// 正弦波类
private byte[] byteDate;
private int len;
private byte[] byteDate1;
private int len1;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
init();
byteDate = new byte[] { 0x71, 0x22, 0x42 };
len = byteDate.length;
byteDate1 = new byte[] { 0x11, 0x22, 0x42, 0x1A, 0x24, 0x13, 0x0a };
len1 = byteDate1.length;
}
private void init() {
btnPlayFS = (Button) findViewById(R.id.btn_play);
btnPlayFL = (Button) findViewById(R.id.btn_play1);
btnPlayZ = (Button) findViewById(R.id.btn_play2);
btnStopZ = (Button) findViewById(R.id.btn_stop);
btnStopZ.setEnabled(false);
btnPlayFS.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if (woF == null) {
woF = new WaveOutF();
}
woF.sendByteDate(byteDate, len);
}
});
btnPlayFL.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (woF == null) {
woF = new WaveOutF();
}
woF.sendByteDate(byteDate1, len1);
}
});
btnPlayZ.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
btnStopZ.setEnabled(true);
btnPlayZ.setEnabled(false);
if (woZ == null) {
woZ = new WaveOutZ();
}
woZ.palyWaveZ();
}
});
btnStopZ.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if (woZ != null) {
woZ.colseWaveZ();
btnPlayZ.setEnabled(true);
btnStopZ.setEnabled(false);
}
}
});
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
if (woZ != null) {
woZ.colseWaveZ();
woZ = null;
}
if (woF != null) {
woF.closeAudioTrack();
woF = null;
}
this.finish();
}
return super.onKeyDown(keyCode, event);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.activity_main, menu);
return true;
}
@Override
protected void onStop() {
super.onStop();
}
}
package scl.waveout;
import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioTrack;
import android.util.Log;
public class WaveOutF {
// private ExecutorService pool = Executors.newSingleThreadExecutor();
private short max_iAmp = Short.MAX_VALUE;// 方波幅度<-32767 ~ 32767>
private short min_iAmp = Short.MIN_VALUE;
private byte[] m_date;// 得到的数据
private int m_lenght;// 得到数据的有效长度
private int m_iFangBo = 58;
private int sampleRateInHz = 44100; // 采样率
private int m_channel = AudioFormat.CHANNEL_CONFIGURATION_MONO;// 声道 :单声道
private int m_sampBit = AudioFormat.ENCODING_PCM_16BIT;// 采样精度 :16bit
private AudioTrack audioTrackF;
private short[] m_bitDateF ;
// AudioTrack创建所需的缓冲区大小
final int bufferSize = AudioTrack.getMinBufferSize(sampleRateInHz, m_channel,
m_sampBit);
public WaveOutF() {
System.out.println(bufferSize+"---------------");
audioTrackF = new AudioTrack(AudioManager.STREAM_SYSTEM,
sampleRateInHz, m_channel, m_sampBit, bufferSize,
AudioTrack.MODE_STREAM);
audioTrackF.setStereoVolume(0.0f, 1.0f);// 设置左右声道音量
// audioTrackF.play();
}
public void sendByteDate(byte[] byteDate, int len) {
if(audioTrackF == null){
Log.i("Fangbo", " null");
}
this.m_date = byteDate;
this.m_lenght = len;
m_bitDateF = null;
m_bitDateF = getShortDate();// audioTrack 播放时的数据
Thread audioTrackFThread = new Thread(new AudioTrackFThread());
// pool.execute(audioTrackThread);
audioTrackFThread.start();
this.m_date = null;
this.m_lenght = 0;
}
// 通过byteDate转为short型 的声音数据
private short[] getShortDate() {
int j = 0;
String strBinary = getstrBinary(this.m_date, this.m_lenght);
int len = strBinary.length();
int m_bitDateSize = len * m_iFangBo;
short[] m_pRightDate = new short[m_bitDateSize];
for (int i = 0; i < len; i++) {
int ct = m_iFangBo;
if (strBinary.charAt(i) == '1') {
while (ct-- > 0) {
// m_pRightDate[j++] = min_iAmp;
m_pRightDate[j++] = max_iAmp;
}
} else {
while (ct-- > 0) {
// m_pRightDate[j++] = max_iAmp;
m_pRightDate[j++] = min_iAmp;
}
}
}
return m_pRightDate;
}
// 将一个字节编码转为2进制字符串
private String getstrBinary(byte[] date, int lenght) {
StringBuffer strDate = new StringBuffer(lenght * 8);
for (int i = 0; i < lenght; i++) {
String str = Integer.toBinaryString(date[i]);
// System.out.println("str:"+str);
while (str.length() < 8) {
str = '0' + str;
}
strDate.append(str);
}
Log.i("strDate: " ,strDate+"");
return strDate.toString();
}
private void playWaveF(short[] m_bitDateF) {
audioTrackF.play();
audioTrackF.write(m_bitDateF, 0, m_bitDateF.length);// 该方法是阻塞的
}
public void closeAudioTrack() {
if (audioTrackF != null) {
audioTrackF.stop();
audioTrackF.release();
}
}
class AudioTrackFThread implements Runnable{
@Override
public void run() {
playWaveF(m_bitDateF);
audioTrackF.flush();
// Log.i("Thread","run over");
}
}
}
package scl.waveout;
import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioTrack;
public class WaveOutZ {
private int sampleRateInHz = 44100; // 采样率
private int mChannel = AudioFormat.CHANNEL_CONFIGURATION_MONO;// 声道 :单声道
private int mSampBit = AudioFormat.ENCODING_PCM_16BIT;// 采样精度 :16bit
private AudioTrackZThread audioTrackZThread;
private boolean isRunning = false;
private AudioTrack audioTrackz;
public WaveOutZ() {
int bufferSize = AudioTrack.getMinBufferSize(sampleRateInHz, mChannel,
mSampBit);
audioTrackz = new AudioTrack(AudioManager.STREAM_SYSTEM,
sampleRateInHz, mChannel, mSampBit, bufferSize * 2,
AudioTrack.MODE_STREAM);
audioTrackz.setStereoVolume(1.0f, 0.0f);
audioTrackz.play();
}
public void palyWaveZ() {
audioTrackZThread = new AudioTrackZThread();
audioTrackZThread.start();
}
public void colseWaveZ() {
if (audioTrackz != null) {
if (!AudioTrackZThread.interrupted()) {
isRunning = false;
}
// audioTrackz.stop();
// audioTrackz.release();
}
}
class AudioTrackZThread extends Thread {
private short m_iAmp = Short.MAX_VALUE;
private short m_bitDateZ[] = new short[44100];
private double x = 2.0 * Math.PI * 8250.0 / 44100.0;
@Override
public void run() {
isRunning = true;
for (int i = 0; i < 44100; i++) {
m_bitDateZ[i] = (short) (m_iAmp * Math.sin(x * i));
}
int m_bitDateZSize = m_bitDateZ.length;
do {
audioTrackz.write(m_bitDateZ, 0, m_bitDateZSize);
// Log.v("isRunn", isRunning+"");
} while (isRunning);
super.run();
}
}
}
发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/128786.html原文链接:https://javaforall.cn
【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛
【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...