音频剪辑的频率和音高关系 - Unity3D

6
我正在尝试仅使用6个音频剪辑来重新创建吉他的完整音域。
我曾考虑过设置音频剪辑的频率,但是audio.frequency仅基于压缩格式返回音频频率而非实际音调。
我知道可以使用GetSpectrumData来读取,但这个解决方案相当复杂,需要进行傅里叶变换分析或类似的东西。
影响音高很容易改变音调以便进行升降,但是否有办法找出要使用的步骤?
void Update () 
{
    CheckAudio(KeyCode.Q, 1.0f);
    CheckAudio(KeyCode.W, 1.1f);
    CheckAudio(KeyCode.E, 1.2f);
    CheckAudio(KeyCode.R, 1.3f);
    CheckAudio(KeyCode.T, 1.4f);
}

void CheckAudio(KeyCode key, float pitch)
{
    if (Input.GetKeyDown (key)) 
    {
        audio.pitch = pitch;
        audio.Play ();
    }
}

我能听出来这不太对。

已知初始音调为E4,频率为329.63Hz,如果要得到下一个音键F4(或接近它),有没有影响音高的方程式呢?

还需要考虑Unity AudioSource将音高限制在-3/3范围内(我认为这超过了需要的范围)。

编辑:添加一些个人研究。似乎音高1是初始音符,将其设为2会得到相同的键,但是高一个八度。

由于半音阶(钢琴上所有黑键和白键)是12个键,我认为每个步骤使用1/12应该就可以了。

听起来很接近,但我感觉还是不太对。下面是新代码:

[SerializeField] private AudioSource audio;
float step = 1f/12f;
KeyCode[]keys = new KeyCode[]{
    KeyCode.Q, KeyCode.W,KeyCode.E,KeyCode.R,KeyCode.T,
    KeyCode.Y, KeyCode.U, KeyCode.I, KeyCode.O, KeyCode.P,
    KeyCode.A, KeyCode.S, KeyCode.D
};

void Update () 
{
    float f = 0.0f;
    foreach (KeyCode key in keys) 
    {
        CheckAudio(key, f);
        f += 1f;
    }
}

void CheckAudio(KeyCode key, float pitch)
{
    if (Input.GetKeyDown (key)) 
    {
        audio.pitch = 1f + pitch * step;
        audio.Play ();
    }
}
1个回答

7
你试图通过简单更改音频的音调来实现的效果不会很好。更改音调会导致其他问题,例如声音结束得太快或需要更长时间才能结束,而且声音也不好听。
第一种解决方案是在C++中制作一个插件(Synthesizer),从Unity读取音频文件并更改频率。它还应该执行其他操作以修复速度问题。这非常复杂,除非你是具有出色数学技能的音频工程师。在移动设备上尝试这个方法则是另一回事了。如果您决定使用此方法,则应使用OnAudioFilterRead函数。
第二种解决方案是为每个吉他键制作一个音频文件,然后将它们放入audioClip数组中。这解决了所有其他问题。缺点是您将拥有更多的文件
编辑:
如果您不在意完美,可以从网络上这位好人提供的以下内容中选择一些。 互联网上的这个好人提供了一些选择。
void playSound(){
     float transpose = -4; 
     float note = -1; 
     if (Input.GetKeyDown("a")) note = 0;  // C
     if (Input.GetKeyDown("s")) note = 2;  // D
     if (Input.GetKeyDown("d")) note = 4;  // E
     if (Input.GetKeyDown("f")) note = 5;  // F
     if (Input.GetKeyDown("g")) note = 7;  // G
     if (Input.GetKeyDown("h")) note = 9;  // A
     if (Input.GetKeyDown("j")) note = 11; // B
     if (Input.GetKeyDown("k")) note = 12; // C
     if (Input.GetKeyDown("l")) note = 14; // D

     if (note>=0){ // if some key pressed...
         audio.pitch =  Mathf.Pow(2, (note+transpose)/12.0);
         audio.Play();
}

编辑:对于那些想知道为什么使用并且有效的Mathf.Pow方程式的人,请阅读以下内容:https://en.wikipedia.org/wiki/Twelfth_root_of_two


是的,我想到了第二种解决方案,但正在寻找是否有更加程序化的方法来避免你提到的缺点。现在你提到了这一点,声音在上升音高时变短可能是需要的。想象一下吉他,当你沿着品格往上走时,弦会变短,共鸣时间也会变短。由于这是一个个人研究项目,我想我会选择一个不完美的解决方案。无论如何,谢谢。 - Everts
@Everts 如果你不在意它有多完美,你可以尝试我刚刚编辑的代码。这不是我写的,但我附上了它来源的链接。我认为这可能是你正在寻找的方程式。 - Programmer
好的,编辑实际上已经足够接近了。我正在与一些在线钢琴进行比较,一切都很顺利。非常感谢你。 - Everts
很高兴我能帮到你。 - Programmer

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