gpt4 book ai didi

java - Android 音频编程噩梦 - soundpool,audiotrack arrghh?

转载 作者:塔克拉玛干 更新时间:2023-11-02 08:53:43 24 4
gpt4 key购买 nike

我构建了一个简单的音乐音序器 Android 应用程序,可以播放多个音频文件。

最初我使用 SoundPool 播放 mp3 文件,它在 2.3.4 上与旧的 HTC Droid Incredible 完美配合。然后我在运行 4.3 的 Galaxy Nexus 上对其进行了测试,性能非常糟糕。到处都是音频时序,并且出现故障/咔哒声/砰砰声。

所以我花了几天时间制作了一个使用 AudioTrack 的播放器,包括一个 mp3 解码器,并让它在 Galaxy 和 HTC 上都能完美运行。现在,我刚刚在 Nexus 4(运行 4.3)上对其进行了测试,性能非常糟糕——时间安排无处不在。 SoundPool 甚至可以在此设备上提供更好的性能。

我真的很沮丧,不知道该怎么做才能完成我的应用程序,所以如果有人能帮助我,我将不胜感激。我在下面放了一些音频播放器的代码示例。我已经尝试了所有我能想到的方法,包括更改缓冲区大小、使用 AudioTrack.MODE_STATIC 等。新的 Google 设备具有低延迟音频,所以很奇怪在我的旧机器人上一切都运行得更好!

提前致谢

/**
* Play note
*/
public void playNote(String note, float vol)
{
PlayThread oldThread = threadMap.get(note);
if(oldThread != null) {
//Cancel timer
if(oldThread.timer != null) {
oldThread.timer.cancel();
oldThread.timer.purge();
oldThread.timer = null;
}
//Stop
oldThread.requestStop();
threadMap.remove(note);
}

//Play if within Polyphony
if(threadMap.size() < POLYPHONY) {
PlayThread thread = new PlayThread(note, vol);
thread.start();
threadMap.put(note, thread);
}
}


/**
* Stop note
*/
public void stopNote(String note, int fadeDurationInMs)
{
PlayThread thread = threadMap.get(note);
if(thread != null) {
thread.fadeOut(fadeDurationInMs);
threadMap.remove(note);
}
}


/**
* Stop all
*/
public void stopAllPlaying(int fadeDurationInMs)
{
for(PlayThread thread : threadMap.values()) {
if(thread != null) {
thread.fadeOut(fadeDurationInMs);
}
}
threadMap.clear();
}


/**
* PlayThread
*/
private class PlayThread extends Thread
{
String note;
float vol;
float fadeVol;
boolean stop;
AudioTrack audioTrack;
Timer timer;

/**
* Constructor
*/
public PlayThread(String note, float vol)
{
super();
this.note = note;
this.vol = vol;
this.fadeVol = vol;
}

/**
* Run
*/
public void run()
{
try {
android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_URGENT_AUDIO);

//Create buffer
int bufferSize = AudioTrack.getMinBufferSize(SAMPLE_RATE, CHANNELS, AudioFormat.ENCODING_PCM_16BIT);
Log.v(Constants.TAG, "min buffersize = " + bufferSize);

bufferSize = bufferSize * 2;

byte[] buffer = new byte[bufferSize];

//AudioTrack
audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, SAMPLE_RATE, CHANNELS, AudioFormat.ENCODING_PCM_16BIT, bufferSize, AudioTrack.MODE_STREAM);
audioTrack.setStereoVolume(vol, vol);
audioTrack.play();

//Get byte data
byte[] byteData = sampleMap.get(note);

//Convert to input stream
InputStream input = new ByteArrayInputStream(byteData);

//Write to audioTrack
int bytesRead = 0;
while(!stop && (bytesRead = input.read(buffer)) != -1) {
audioTrack.write(buffer, 0, bytesRead);
}

//When finished...
audioTrack.stop();
audioTrack.release();
input.close();
killThread(this);
}
catch(Exception e) {}
}

/**
* Set volume
*/
private synchronized void setVol(float newVol)
{
audioTrack.setStereoVolume(newVol, newVol);
}

/**
* Update volume
*/
private synchronized void lowerVol()
{
fadeVol -= 0.01;
if(fadeVol < 0) vol = 0;
audioTrack.setStereoVolume(fadeVol, fadeVol);
}

/**
* Fade out
*/
public synchronized void fadeOut(int fadeDurationInMs)
{
//Start decreasing volume
if(fadeDurationInMs > 0) {
timer = new Timer(true);
TimerTask timerTask = new TimerTask()
{
@Override
public void run()
{
//If thread killed while running
try {
//Lower volume
lowerVol();
}
catch (Exception e) {}

//Stop when volume reaches 0
if(fadeVol <= 0) {
if(timer != null) {
timer.cancel();
timer.purge();
}
stop = true;
}
}
};

//Calculate delay, set to 1 if zero
int delay = (int) (fadeDurationInMs / (vol * 100));
if(delay == 0) delay = 1;

timer.schedule(timerTask, delay, delay);
}
}

/**
* Request stop
*/
public synchronized void requestStop()
{
//Stop click/pop when stopping sample
setVol(0.01f);
setVol(0.005f);
stop = true;
}

/**
* Kill Thread
*/
private synchronized void killThread(Thread theThread)
{
if(theThread != null) {
theThread = null;
}
}

}

最佳答案

正如用户 harikris 所建议的,我强烈建议您使用 OpenSL ES 库将所有​​音频播放和处理代码移至 Android NDK 以获得最佳性能。

据我了解,AudioTrack API 构建于 OpenSL ES 缓冲队列音频播放器之上。因此,您可能可以通过直接使用 NDK 来提高性能,编写从 Java/Android 层调用的 C 代码来处理声音。

上面提到的 native 音频示例包含的代码将向您展示如何直接从 URI 播放声音文件。根据我的经验,这种方法的结果比静态模式下的 AudioTrack 更好。

Soundpool 通常用于可以从内存中播放的非常短的声音,它不是一个可扩展的音序器解决方案,尤其是当您引入大文件时。

以下是一些帮助我完成申请的链接:- Android 版 OpenSL ES 的一般信息: http://mobilepearls.com/labs/native-android-api/opensles/

- 一个 Android 音频博客,其中包含一些很棒的示例代码: http://audioprograming.wordpress.com

编辑:旧的移动珍珠链接似乎已关闭。这是一个有效的:http://mobilepearls.com/labs/native-android-api/ndk/docs/opensles/index.html

关于java - Android 音频编程噩梦 - soundpool,audiotrack arrghh?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18794965/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com