Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Frequency and pitch relation for AudioClip - Unity3D

I am trying to recreate the full range of a guitar only using 6 audio clips.

I was thinking there would be a way to set frequency of an audio clip but audio.frequency only returns the frequency of the audio based on compression format and not the actual tone.

I know I can read GetSpectrumData, but that solution is fairly complex and would require some Fourier Transform analysis or something of the kind.

Affecting the pitch, it is easy to alter the tone so I can go up and down but is there a way to figure out what are the steps to use.

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 ();
    }
}

I can hear it does not sound right.

Knowing the initial tone E4 329.63Hz with pitch at 1 is there any equation that affecting the pitch, I would get the next key F4 349.23Hz (or close enough)?

It has to be considered also that Unity AudioSource limits the pitch within -3/3 range (which I think is more than needed).

EDIT: Adding some personal research. It seems pitch 1 is initial note and setting to 2 give the same key one octave higher.

Since a chromatic scale (all black and white notes on the piano) is 12 keys, I assume that using 1/12 for each step should do it.

It sounds close but I fell it is not quite right. Here is the new code:

[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 ();
    }
}
like image 363
Everts Avatar asked Apr 22 '16 12:04

Everts


People also ask

How do you play an AudioClip in unity?

Unity has a built in method for triggering events when a button is pressed and this includes an option for playing an Audio Clip. Just create an On Click event trigger, drag a Game Object to the object field and select PlayOneShot(AudioClip) from the Audio Source section of the drop down menu.

What is unity pitch?

Pitch is a quality that makes a melody go higher or lower. As an example imagine playing an audio clip with pitch set to one. Increasing the pitch as the clip plays will make the clip sound like it is higher. Similarly decreasing the pitch less than one makes the clip sound lower.

What is AudioSource unity?

An AudioSource is attached to a GameObject for playing back sounds in a 3D environment. In order to play 3D sounds you also need to have a AudioListener. The audio listener is normally attached to the camera you want to use.


1 Answers

What you are trying to do will not work well by simply changing the pitch of the audio. By changing the pitch, you will run into other problems such as sound finishing too fast or taking more time to finish and the sound will not be good either.

The first solution is to make a plugin(Synthesizer) in C++ that reads the audio file from Unity and change the frequency. It should also perform other actions to fix speed issues. This is very complicated unless you are an audio engineer with some great math skills. And trying this on a mobile device is whole different story. OnAudioFilterRead is a function you should use if you decide to go with this method.

The second and the recommended solution is to make an audio file for each guitar key then put them into array of audioClip. This solves every other problems.The down side is that you will have more files.

EDIT:

If you don't care about it being perfect, you can use something below from this nice guy on the internet.

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();
}

EDIT: For those of you interested in why the Mathf.Pow equation is used and working, read the following: https://en.wikipedia.org/wiki/Twelfth_root_of_two

like image 51
Programmer Avatar answered Oct 15 '22 09:10

Programmer