【问题标题】:Play three or more short sounds in exact time SoundPool(piano chord)在精确的时间播放三个或更多的短音 SoundPool(钢琴和弦)
【发布时间】:2017-12-05 10:46:44
【问题描述】:

我有一个问题,我想同时启动声音。

我循环播放 3-5 个短音(钢琴音),前 1 毫秒,第二个 17 毫秒,依此类推,最后一个声音最多 60-90 毫秒。

我正在使用 SoundPool。

有人遇到过这样的问题或使用过可以解决此问题的库(同步启动多个短音)吗?

以下是示例测试示例(我使用 RxJava,但我在使用和不使用 RxJava 的情况下对其进行了测试):

   Observable.timer(150, TimeUnit.MILLISECONDS, Schedulers.single())
            .repeat()
            .subscribe(aLong -> {
                for (int soundId = 55; i < 60; i++) {
                    soundPool.play(soundId , 1f, 1f, 1, 0, 1);
                }
            });

【问题讨论】:

    标签: android audio soundpool


    【解决方案1】:

    您似乎需要实现 listener (OnLoadCompleteListener)SoundPool 如文档中所述异步加载音频文件,因此我相信这就是您延迟的原因。

    找到了 3 个声音的这个工作示例here

    public class SoundManager {
    
        public static int SOUNDPOOLSND_MENU_BTN         = 0;
        public static int SOUNDPOOLSND_WIN              = 1;
        public static int SOUNDPOOLSND_LOOSE            = 2;
        public static int SOUNDPOOLSND_DRAW             = 3;
        public static int SOUNDPOOLSND_TICK1            = 4;
        public static int SOUNDPOOLSND_TICK2            = 5;
        public static int SOUNDPOOLSND_OUT_OF_TIME      = 6;
        public static int SOUNDPOOLSND_HISCORE          = 7;
        public static int SOUNDPOOLSND_CORRECT_LETTER   = 8;
    
        public static boolean isSoundTurnedOff;
    
        private static SoundManager mSoundManager;
    
        private SoundPool mSoundPool; 
        private SparseArray <Integer> mSoundPoolMap; 
        private AudioManager  mAudioManager;
    
        public static final int maxSounds = 4;
    
        public static SoundManager getInstance(Context context)
        {
            if (mSoundManager == null){
                mSoundManager = new SoundManager(context);
            }
    
            return mSoundManager;
       }
    
        public SoundManager(Context mContext)
        {
            mAudioManager = (AudioManager)mContext.getSystemService(Context.AUDIO_SERVICE);
            mSoundPool = new SoundPool(maxSounds, AudioManager.STREAM_MUSIC, 0);
    
          mSoundPool.setOnLoadCompleteListener(new OnLoadCompleteListener() {
              public void onLoadComplete(SoundPool soundPool, int sampleId,int status) {
                loaded = true;
                }
            });
    
            mSoundPoolMap = new SparseArray<Integer>(); 
            mSoundPoolMap.put(SOUNDPOOLSND_MENU_BTN, mSoundPool.load(mContext, R.raw.menubutton, 1));
            mSoundPoolMap.put(SOUNDPOOLSND_WIN, mSoundPool.load(mContext, R.raw.win, 1));
            mSoundPoolMap.put(SOUNDPOOLSND_LOOSE, mSoundPool.load(mContext, R.raw.lose, 1));
            mSoundPoolMap.put(SOUNDPOOLSND_TICK1, mSoundPool.load(mContext, R.raw.tick_0, 1));
            mSoundPoolMap.put(SOUNDPOOLSND_TICK2, mSoundPool.load(mContext, R.raw.tick_1, 1));
            mSoundPoolMap.put(SOUNDPOOLSND_OUT_OF_TIME, mSoundPool.load(mContext, R.raw.out_of_time, 1));
            mSoundPoolMap.put(SOUNDPOOLSND_HISCORE, mSoundPool.load(mContext, R.raw.personal_highscore, 1));
            mSoundPoolMap.put(SOUNDPOOLSND_CORRECT_LETTER, mSoundPool.load(mContext, R.raw.correct_letter, 1));
    
            // testing simultaneous playing
            int streamVolume = mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC); 
            mSoundPool.play(mSoundPoolMap.get(0), streamVolume, streamVolume, 1, 20, 1f); 
            mSoundPool.play(mSoundPoolMap.get(1), streamVolume, streamVolume, 1, 2, 1f);
            mSoundPool.play(mSoundPoolMap.get(2), streamVolume, streamVolume, 1, 0, 1f);
    
    
        } 
    
        public void playSound(int index) { 
            if (isSoundTurnedOff)
                return;
    
             int streamVolume = mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC); 
             mSoundPool.play(mSoundPoolMap.get(index), streamVolume, streamVolume, 1, 0, 1f); 
        }
    
        public static void clear()
        {
            if (mSoundManager != null){
                mSoundManager.mSoundPool = null; 
                mSoundManager.mAudioManager = null;
                mSoundManager.mSoundPoolMap = null;
            }
            mSoundManager = null;
        }
    }
    

    【讨论】:

    • 声音已加载,我认为可能是线程/同步问题
    • 嗯,我在网上看到这样的解决方案,人们使用两个线程并尝试将它们同步为两个声音,但它看起来不对
    • 反之,就是把声音混在一起,作为一个播放,也是一种常见的方案
    • 我已经测试了多种解决方案,我认为我必须尝试使用​​适用于 Android 的 OpenSL ES 的 NDK
    • 如果您使用的是原始 PCM-16 位样本,您可以尝试使用简单易用的 AudioTrack,只需将同时播放的所有样本相加并尝试通过削波或应用小于 1 的增益来限制输出(通过简单地相乘)以避免削波。这样您就可以为所有音频使用单个音频输出,否则您的系统必须为您执行此操作,即将所有音频输出混合为一个。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多