Android输出正弦波音频信号(左右声道对称)


转载请说明出处!
作者:kqw攻城狮
出处:个人站 | CSDN


需求:左右声道分别输出不同的音频数据,波形要是一个正弦波,左右声道还要对称!
对硬件不是很了解,说是要通过音波避障。

效果图

效果图

之前已经介绍了如何在左右声道输出不同的音频数据。
那么这里主要介绍如何模拟出波形是正弦波的音频数据。

模拟正弦波

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/**
* 模拟正弦波音频数据
* @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:采样率
1
2
3
4
5
6
// 单声道
private int mChannelConfig = AudioFormat.CHANNEL_OUT_MONO;
// 频率
private int mFrequency = 19000;
// 采样率
private int mSampleRateInHz = 44100;

播放音频的线程封装

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
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;
}
}
}

播放

1
2
3
4
5
mLeftChannelThread = new ChannelThread(mChannelConfig, mSampleRateInHz, mDataLeft, bufferSize, true);
mRightChannelThread = new ChannelThread(mChannelConfig, mSampleRateInHz, mDataRight, bufferSize, false);
mLeftChannelThread.start();
mRightChannelThread.start();

停止

1
2
3
4
5
6
7
8
if (null != mLeftChannelThread) {
mLeftChannelThread.releaseAudioTrack();
mLeftChannelThread = null;
}
if (null != mRightChannelThread) {
mRightChannelThread.releaseAudioTrack();
mRightChannelThread = null;
}

不足

这里介绍的是在程序中模拟出一个波形满足正弦波的音频数据,还有一种方式,可以事先准备好一个这样的音频文件,直接播放就可以了。

在程序中模拟音频数据有一个缺点,就是不能保证两个线程完完全全的同步,即便是同时开启两个线程也有一先一后,在频率很高的时候,难免会有一点误差!像下面这样:

误差图

另外,这个波形和硬件有很大关系,越是低配设备,误差可能会越大,相同的趋势,但是波动的幅度会比较大(线很粗),可能和设备本身的噪音有关系。

坚持原创技术分享,您的支持将鼓励我继续创作!