14

我正在使用 Android 开发游戏,但遇到了一个非常烦人且难以发现的错误。问题是当你SoundPool用来播放声音时,你实际上可以循环播放你正在播放的任何声音。在这种情况下,问题是“运行步骤”的声音;400ms当主角正在奔跑时,这种声音会非常快速且持续地(围绕 every )执行。

现在,当在常规(不是那么强大)设备(例如三星 SII)上播放声音时,每次都会播放声音500ms- 但是,如果我在另一台设备(比如三星 SIV、三星 SIII)上运行相同的代码,声音就会播放快两倍甚至三倍。

似乎设备硬件规格越强大,播放速度就越快。在某些设备上,它的播放速度非常快,您几乎可以听到一种连续的声音。我一直在寻找在声音播放之间设置特定比率的技术,但它不能正常工作并且问题仍然存在。有谁知道如何修复它,无论是使用SoundPool,MediaPlayer还是 Android 上的任何其他声音控制 API?

4

5 回答 5

1

您可以使用AudioTrack播放连续的 PCM 数据流,因为您将传递一个流,您可以确定声音之间的间隔。缺点可能是第一次启动声音时会有一点延迟,但这取决于最小缓冲区大小,我认为这取决于 android 版本和设备。在我的 Galaxy s2 android 4.1 上大约是 20 毫秒。
如果您认为这可能是一个选项,我可以发布一些代码

于 2013-09-25T17:37:09.427 回答
1

仅循环播放或对诸如脚步声之类的内容使用定期间隔的问题在于,您可能会分离声音和视觉效果。如果您的声音延迟或加速,或者您的视觉效果延迟或加速,您将不得不动态地自动调整该延迟。您已经在这里遇到了这个问题

更好的解决方案是在应该触发声音的确切事件上放置一个触发器(在这种情况下,脚被放下),然后播放声音。这也意味着,如果您有多个声音源(例如多个脚步声),您不必手动以正确的间隔开始声音。

于 2013-10-15T14:49:38.653 回答
0

我在开发使用声音之类的应用程序时遇到了很多问题。我不建议您使用 SoundPool,因为它受 bug 影响,并且还请注意,使用 SoundPool 循环声音将无法在 4.3 及更高版本的设备上运行,请参阅AOSP - Issue tracker 中的这个开放问题。我认为解决方案是原生并使用 OpenSL ES o 类似的库。

于 2013-12-30T19:03:22.233 回答
0

我似乎无法在 Galaxy Nexus 和 Nexus S 上复制该问题,这是否意味着我已修复?或者,也许您可​​以展示您正在做的与此不同的事情:

SoundPool soundPool = new SoundPool(4, AudioManager.STREAM_MUSIC, 100);
Integer sound1 = soundPool.load(this, R.raw.file1, 1);
Integer sound2 = soundPool.load(this, R.raw.file2, 1);
playSound(sound1);

public void playSound(int sound) {
  AudioManager mgr = (AudioManager)getSystemService(Context.AUDIO_SERVICE);
  float volume = mgr.getStreamVolume(AudioManager.STREAM_MUSIC)
               / mgr.getStreamMaxVolume(AudioManager.STREAM_MUSIC);  
  soundPool.play(sound, volume, volume, 1, -1, 1.0f);
}
于 2013-10-16T18:42:19.980 回答
0

如果问题是您想控制离散声音之间的间隔,最简单的方法是使用处理程序。

基本上,您开始播放声音,这是一个异步过程。然后,您使用处理程序安排消息在未来某个时间播放下一个声音。需要一些试验和错误才能使其正确,但您可以保证声音将在每台设备上的前一​​个声音之后以相同的间隔开始。

这是一些代码来说明我在说什么。

这是您可以使用的处理程序实现:

    handler = new Handler() {

        /* (non-Javadoc)
         * @see android.os.Handler#handleMessage(android.os.Message)
         */
        @Override
        public void handleMessage(Message msg) {
            if (msg.what == NEXT_ITEM_MSG) {
                playNextSound();
            }
            else if (msg.what == SEQUENCE_COMPLETE_MSG) {
                // notify a listener
                listener.onSoundComplete()
            }
        }
    };

然后你可以这样写 playNextSound:

private void playNextSound() {
    if (mRunning) {
        // Get the first item
        SoundSequenceItem item = currentSequence.getNextSequenceItem();
        if (item == null) {
            Message msg = handler.obtainMessage(SEQUENCE_COMPLETE_MSG);
            handler.sendMessage(msg);
            return;
        }
        // Play the sound
        int iSoundResId = item.getSoundResId();
        if (iSoundResId != -1) {
            player.playSoundNow(soundResId);
        }

        // schedule a message to advance to next item after duration
        Message msg = handler.obtainMessage(NEXT_ITEM_MSG);
        handler.sendMessageDelayed(msg, item.getDuration());
    }
}

并且您的 SoundSequenceItem 可能只是一个具有声音文件资源 ID 和持续时间的简单类。如果您想在角色移动时继续播放声音,您可以执行以下操作:

public void onSoundComplete() {
    if (character.isRunning()) {
        currentSequence.addSequenceItem(new SoundSequenceItem(R.id.footsteps,500);
        playNextSound();
    }
}

或者您可以修改 playNextSound 以连续播放相同的声音。我是这样写的,以便能够按顺序播放不同的声音。

于 2013-10-16T19:26:28.030 回答