【问题标题】:Android audio : change pitchAndroid 音频:改变音高
【发布时间】:2011-12-17 20:56:44
【问题描述】:

SoundPool 的 Android 文档说“该应用程序还可以通过实时调整多普勒或合成效果的播放速率来改变音高”。所以我尝试这样做,使用 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
  • 你如何测试你的代码。如果您使用的是真实设备,则您的设备可能太慢而无法动态更改播放速率。如果您使用的是模拟器,则问题可能出在您主机的声卡上。更改播放速率并非易事,可能需要复杂的插值,尤其是在以非标准转换速率运行时。
  • 我在设备 (Galaxy S) 和模拟器上都进行了测试。在设备上听起来更糟,但在模拟器中声音也被“切碎”了。
  • 增加速率增量之间的时间是否会变得更好?说SystemClock.sleep(100);?
  • 如果增量较慢,缺陷就不太明显,但这无济于事,因为我需要足够快地改变音高,以模拟乐器(例如吉他、小提琴)。

标签: android audio signal-processing soundpool


【解决方案1】:

尽管 Androids 文档建议您可以使用 setRate() 来产生多普勒效应,但我不会依赖于每个 android 设备上的快速或足够好的实现。

经济实惠的音频 IC 需要 44kHz 或 48kHz 的固定采样率。因此,采样率转换(即音高修改)必须在软件中完成。因为这包括低级数字运算,所以我确信这是由设备制造商实现的,而不是由 Google 实现的。鉴于 Android 设备制造商种类繁多,并且使用的硬件通常成本较低,因此肯定有许多采样率转换实现。有些快,有些慢。有些光滑,有些粗糙。

在播放期间更改转换率会发生什么?如果算法不能将这些片段精确地匹配在一起,那么您的音频播放中可能会出现短暂的裂缝。您每 10 毫秒更改一次转换率。如果每 10ms 有一个裂纹,则对应于 100Hz 的频率,它本身就是一个音调。这很可能就是您所听到的“衣衫褴褛”。

总而言之,我认为使用高级 Android API 在各种 Android 设备上实时模拟乐器是不可能的。不过,本机应用程序可能已经足够快了。

【讨论】:

    【解决方案2】:

    在尝试了所有方法之后,我决定使用 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);
             }
    
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2021-10-26
      • 2023-03-29
      • 1970-01-01
      • 2012-01-20
      • 2013-09-30
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多