安卓音频:改变音调

6

Android文档中的SoundPool说明:“应用程序还可以通过实时调整播放速率来改变音高,以实现多普勒或合成效果”。因此,我尝试使用setRate方法平滑地从一个音符变化到另一个音符,但结果很糟糕:声音变化非常不平滑。以下是我尝试的代码。请告诉我是否有更好的方法。

int streamId = soundPool.play (soundId, 1, 1, 1, 0, 1.0f);
for (float x = 0; x < 1; x += 0.005) {
  SystemClock.sleep (10);
  soundPool.setRate (streamId, 1 + x);
}

1 + x 更改为 1.0f + x,并且(也将 0.005 更改为 0.005f)。 - Sherif elKhatib
你是如何测试你的代码的?如果你正在使用真实设备,可能会出现设备过慢以至于无法动态改变播放速率的情况。如果你正在使用模拟器,问题可能出在你主机的声卡上。改变播放速率并不是一项简单的任务,尤其是在非标准转换速率下运行时,可能需要复杂的插值处理。 - MBober
我在设备(Galaxy S)和模拟器上都进行了测试。在设备上听起来更糟糕,但在模拟器上声音也会“断断续续”。 - Patrick
当你增加速率增量之间的时间时,情况会变得更好吗?比如说 SystemClock.sleep(100); - MBober
如果增量较慢,则缺陷不太明显,但这并没有帮助,因为我需要足够快地改变音高,以模拟乐器(例如吉他、小提琴)。 - Patrick
根据我的经验,SoundPool仅提供短音频的功能,请纠正我如果我错了。 - Baimyrza Shamyr
2个回答

13
尽管Android文档建议您使用setRate()来产生多普勒效果,但我不会依赖每个Android设备上快速或足够好的实现。
经济实惠的音频IC需要固定的44kHz或48kHz采样率。因此,必须在软件中进行采样率转换(即音高修改)。因为这包括低级别的数字处理,所以我确信设备制造商而不是谷歌来实现此功能。鉴于Android设备制造商的广泛多样性和常常使用的低成本硬件,肯定存在许多采样率转换实现。一些更快,一些更慢。有些平滑,有些粗糙。
当在播放过程中改变转换率时会发生什么?如果算法没有将片段精确地匹配在一起,您的音频播放可能会出现短暂的裂缝。您每10毫秒更改一次转换率。如果每10ms出现一次裂缝,则相应的频率为100Hz,这本身就是一个音调。这很可能是您听到的“粗糙”。
总之,我认为使用高级Android API在广泛的Android设备上实时模拟乐器是不可能的。但是本地应用程序可能足够快。

0
尝试了一切后,我决定使用SoundPool来改变音高。播放速率为2.0会使声音以其原始频率的两倍播放,而播放速率为0.5会使其以原始频率的一半播放。播放速率范围为0.5至2.0。但是它可以在低于0.5和高于2.0的频率下工作。
我发布了我的工作代码,但由于它只是演示目的,每次安装应用程序时都需要手动更改“播放速率”,例如:“sp.play(explosion, 1,1,0,0,1.5f)”,这里的“1.5f”是播放速率。人们可以轻松地创建一个EditView或类似的东西,在运行时设置播放速率的值。
在此应用中,您只需点击应用程序屏幕即可以设置的播放速率播放音乐。
import java.io.IOException;

import android.app.Activity;
import android.content.res.AssetFileDescriptor;
import android.media.AudioManager;
import android.media.SoundPool;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;

public class SoundPoolActivity extends Activity implements OnClickListener {

    SoundPool sp;
    int explosion = 0;

    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

       View v = new View(this);
       v.setOnClickListener(this);
       setContentView(v);
       sp = new SoundPool(1,AudioManager.STREAM_MUSIC,0);
       //explosion = sp.load(this, R.raw.hh,0);
       explosion = sp.load("/sdcard/hh.m4a",0);


    }


    public void onClick(View v){
         if (explosion!=0){

             sp.play(explosion, 1,1,0,0,2.3f);
         }

    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接