我有一个功能,我想过渡到使用安卓AudioTrack
而不是MediaPlayer
,由于MediaPlayer
的一些众所周知的bug,例如在循环轨迹之间出现的小间隙。
有人推荐我使用AudioTrack
,但在使用中并没有找到很多这样的例子。我确实发现了一个关于AudioTrack
的问题,并使用了其中的一些代码来破解一些东西:
public class TestActivity extends Activity implements Runnable {
Button playButton;
byte[] byteData = null;
int bufSize;
AudioTrack myAT = null;
Thread playThread = null;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test);
playButton = (Button) findViewById(R.id.testButton);
InputStream inputStream = getResources().openRawResource(R.raw.whitenoise_wav);
try {
byteData = new byte[ inputStream.available()];
} catch (IOException e) {
e.printStackTrace();
}
try {
inputStream.read(byteData);
inputStream.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
initialize();
playButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
playThread.start();
}
});
}
void initialize() {
bufSize = android.media.AudioTrack.getMinBufferSize(44100,
AudioFormat.CHANNEL_CONFIGURATION_STEREO,
AudioFormat.ENCODING_PCM_16BIT);
myAT = new AudioTrack(AudioManager.STREAM_MUSIC,
44100, AudioFormat.CHANNEL_CONFIGURATION_STEREO,
AudioFormat.ENCODING_PCM_16BIT, bufSize,
AudioTrack.MODE_STREAM);
myAT.setVolume(.2f);
playThread = new Thread(this);
}
public void run() {
if (myAT != null) {
myAT.play();
myAT.setLoopPoints(0, byteData.length, 6);
myAT.write(byteData, 0, byteData.length);
}
}
}
因此,这似乎是播放整个音轨(约1:00分钟),然后停止。现在这里的最终目标是两个有两个独立的音轨同时播放和循环。我目前在/res/raw/
目录中有音轨,但如果这样更好的话,我可以将它们移到一个简单的assets
文件夹中。我当前的AudioTrack
实现是否正确?如果是这样,我如何让它循环?
总结:如何使用AudioTrack
播放没有间隙的循环音频
欢迎使用其他方法获取循环音频,例如第三方库。
发布于 2016-04-05 15:14:22
您不能使用配置了AudioTrack.MODE_STREAM
的AudioTrack进行循环。如果使用MODE_STREAM
,则需要不断使用新样本填充AudioTrack。
但是你可以用AudioTrack.MODE_STATIC
来配置它,并传递整个要播放的缓冲区(我的意思是:如果你需要混合两个样本,你必须传递混合的样本)。
setLoopPoints:设置环点和环数。循环可以是无限的。与setPlaybackHeadPosition类似,必须停止或暂停轨迹才能更改循环点,并且必须使用MODE_STATIC模式。
请注意,AudioTrack播放原始的PCM样本,不支持WAV,MP3或其他容器。
发布于 2016-04-12 06:33:11
看看this的例子,这似乎是一个类似的问题,解决了连续供给AudioTrack
的问题。
class ToneGenerator {
int sampleRate = 8000;
double sample[] = null;
byte generatedSnd[] = null;
int m_ifreq = 400;
Thread m_PlayThread = null;
boolean m_bStop = false;
AudioTrack m_audioTrack = null;
int m_play_length = 1000;//in seconds
static public void PlayTone(int freq, int play_length) {
ToneGenerator player = new ToneGenerator();
player.m_ifreq = freq;
player.m_play_length = play_length;
player.play();
}
synchronized void stop() {
m_bStop = true;
if (m_PlayThread != null) {
try {
m_PlayThread.interrupt();
m_PlayThread.join();
m_PlayThread = null;
} catch (Exception e) {
}
}
if (m_audioTrack != null) {
m_audioTrack.stop();
m_audioTrack.release();
m_audioTrack = null;
}
}
synchronized void play() {
m_bStop = false;
m_PlayThread = new Thread() {
public void run() {
try {
int iToneStep = 0;
m_audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC,
sampleRate, AudioFormat.CHANNEL_OUT_MONO,
AudioFormat.ENCODING_PCM_16BIT, 2 * sampleRate,
AudioTrack.MODE_STREAM);
while (!m_bStop && m_play_length-- > 0) {
genTone(iToneStep++);
m_audioTrack.write(generatedSnd, 0, generatedSnd.length);
if (iToneStep == 1) {
m_audioTrack.play();
}
}
} catch (Exception e) {
Log.e("Tone", e.toString());
} catch (OutOfMemoryError e) {
Log.e("Tone", e.toString());
}
}
};
m_PlayThread.start();
}
//Generate tone data for 1 seconds
synchronized void genTone(int iStep) {
sample = new double[sampleRate];
for (int i = 0; i < sampleRate; ++i) {
sample[i] = Math.sin(2 * Math.PI * (i + iStep * sampleRate) / (sampleRate / m_ifreq));
}
// convert to 16 bit pcm sound array
// assumes the sample buffer is normalised.
generatedSnd = new byte[2 * sampleRate];
int idx = 0;
for (final double dVal : sample) {
// scale to maximum amplitude
final short val = (short) ((dVal * 32767));
// in 16 bit wav PCM, first byte is the low order byte
generatedSnd[idx++] = (byte) (val & 0x00ff);
generatedSnd[idx++] = (byte) ((val & 0xff00) >>> 8);
}
}
}
发布于 2016-04-12 09:16:50
您传入的是流的字节长度。setLoopPoints()需要流中的音频块的数量。请参阅文档中的getBufferSizeInFrames()。
然而。我提醒你,大多数特殊的音频格式不是基于块的;它们是基于样本的。MP3是唯一的例外;它在1152字节边界上对齐。如果源内容是MP3,并且没有显式地编写为块对齐,那么无缝循环是不可能的。您似乎正在使用"whitenoise.wav“作为音频源。除非此文件的长度显式地与块大小对齐,否则在循环时可能会出现音频伪影。
解决这个问题的办法是在循环时交叉淡出开始和结束的帧块,并自己处理所有的缓冲,但是你必须自己编写代码来做这件事。
https://stackoverflow.com/questions/36191636
复制相似问题