轉載請說明出處!
作者:kqw攻城獅
出處:個人站 | CSDN
需求:左右聲道分別輸出不同的音頻數據,波形要是一個正弦波,左右聲道還要對稱!
對硬件不是很瞭解,說是要通過音波避障。
效果圖
之前已經介紹瞭如何在左右聲道輸出不同的音頻數據。
那麼這裏主要介紹如何模擬出波形是正弦波的音頻數據。
模擬正弦波
/**
* 模擬正弦波音頻數據
* @param isLeft 左右聲道
* @return 音頻數據
*/
private short[] initData(boolean isLeft) {
double phase = 0.0;
int amp = 10000;
short[] data = new short[bufferSize];
double phaseIncrement = (2 * Math.PI * mFrequency) / mSampleRateInHz;
for (int i = 0; i < bufferSize; i++) {
if (isLeft) {
data[i] = (short) (amp * Math.sin(phase));
} else {
data[i] = (short) (-amp * Math.sin(phase));
}
phase += phaseIncrement;
Log.i(TAG, "initData: isLeft = " + isLeft + " buffer[" + i + "] = " + data[i]);
}
return data;
}
主要參數
- mFrequency:頻率
- mSampleRateInHz:採樣率
// 單聲道
private int mChannelConfig = AudioFormat.CHANNEL_OUT_MONO;
// 頻率
private int mFrequency = 19000;
// 採樣率
private int mSampleRateInHz = 44100;
播放音頻的線程封裝
package kong.qingwei.myapplication;
import android.annotation.TargetApi;
import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioTrack;
import android.os.Build;
import android.util.Log;
/**
* Created by kqw on 2016/8/29.
* 播放音樂的線程
*/
public class ChannelThread extends Thread {
private static final String TAG = "ChannelThread";
private AudioTrack mAudioTrack;
private short[] mData;
/**
* 構造方法
*
* @param channelConfig 聲道
* @param sampleRateInHz 採樣率
* @param data 音頻數據
* @param bufferSize 緩存大小
* @param isLeft 左右聲道
*/
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public ChannelThread(int channelConfig, int sampleRateInHz, short[] data, int bufferSize, boolean isLeft) {
mData = data;
mAudioTrack = new AudioTrack(
AudioManager.STREAM_MUSIC,
sampleRateInHz,
channelConfig,
AudioFormat.ENCODING_PCM_16BIT,
bufferSize,
AudioTrack.MODE_STREAM);
if (isLeft) {
mAudioTrack.setStereoVolume(AudioTrack.getMaxVolume(), 0);
} else {
mAudioTrack.setStereoVolume(0, AudioTrack.getMaxVolume());
}
}
@Override
public void run() {
super.run();
try {
if (null != mAudioTrack) {
mAudioTrack.play();
while (AudioTrack.PLAYSTATE_STOPPED != mAudioTrack.getPlayState()) {
mAudioTrack.write(mData, 0, mData.length);
}
}
Log.i(TAG, "run: End");
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 釋放AudioTrack
*/
public void releaseAudioTrack() {
if (null != mAudioTrack) {
mAudioTrack.stop();
mAudioTrack.release();
mAudioTrack = null;
}
}
}
播放
mLeftChannelThread = new ChannelThread(mChannelConfig, mSampleRateInHz, mDataLeft, bufferSize, true);
mRightChannelThread = new ChannelThread(mChannelConfig, mSampleRateInHz, mDataRight, bufferSize, false);
mLeftChannelThread.start();
mRightChannelThread.start();
停止
if (null != mLeftChannelThread) {
mLeftChannelThread.releaseAudioTrack();
mLeftChannelThread = null;
}
if (null != mRightChannelThread) {
mRightChannelThread.releaseAudioTrack();
mRightChannelThread = null;
}
不足
這裏介紹的是在程序中模擬出一個波形滿足正弦波的音頻數據,還有一種方式,可以事先準備好一個這樣的音頻文件,直接播放就可以了。
在程序中模擬音頻數據有一個缺點,就是不能保證兩個線程完完全全的同步,即便是同時開啓兩個線程也有一先一後,在頻率很高的時候,難免會有一點誤差!像下面這樣:
另外,這個波形和硬件有很大關係,越是低配設備,誤差可能會越大,相同的趨勢,但是波動的幅度會比較大(線很粗),可能和設備本身的噪音有關係。