Search Unity

Audio PlayOneShot pitch

Discussion in 'Audio & Video' started by SparrowGS, Jul 3, 2019.

  1. SparrowGS

    SparrowGS

    Joined:
    Apr 6, 2017
    Posts:
    2,536
    Is there really no way of sending PlayOneShot a value for pitch like you do volume?

    spent forever searching the web...

    The way I see it I have two options:

    1) make a pool of sound sources and use the normal Play.

    2) make a few pitch variations of the same clip in cubase and import it into unity, randomly select a clip instead of a pitch value.

    I'm not whole with either of these solutions as one requires more game objects and more logic (not that i have a problem writing this system, the overhead), and the second requires more disk space (I guess maybe I could make the different clips on program start...) and is slower to iterate on.

    On the other hand.. maybe the second option isn't all that bad, in the editor have a class/stuct that hold a clip with an array of floats for pitch, on program start generate the required clips (never done it but i don't think it's gonna be that hard, I have a decent understanding of sound), make a couple editor scripts to help manage that.. could be a good solution.. what do you guys think?

    I just really wish PlayOneShot could take a pitch parameter.
     
  2. JLF

    JLF

    Joined:
    Feb 25, 2013
    Posts:
    140
    Play one shot respects the audio source pitch settings so you can change the pitch on the source whenever you call play one shot. The limitation is that you can only use one pitch at any one time. So I don’t know if that’s of any use to you or not.
     
  3. SparrowGS

    SparrowGS

    Joined:
    Apr 6, 2017
    Posts:
    2,536
    I'm aware of that, but if I want to play the same sound (gun fire) over itself, I need each one to have its own pitch.

    thanks for replying though. (;
     
    DungDajHjep likes this.
  4. BlackOpsBen

    BlackOpsBen

    Joined:
    Jan 19, 2020
    Posts:
    5
    I'm in the same boat. I think what I am going to do to avoid changing the pitch on a sound mid-play is have a pool of audio sources so that it's unlikely I'll ever need one while it's still in use.
     
  5. Atjowt

    Atjowt

    Joined:
    Apr 8, 2021
    Posts:
    1
    I hade the same issue, wanting to play sounds with different pitch but the pitches overlapping each other. I came up with a (maybe not so performant) solution of instantiating a prefab with an audio source for every sound effect. Here is the code:
    Code (CSharp):
    1. using UnityEngine;
    2. [RequireComponent(typeof(AudioSource))]
    3. public class AudioManager : MonoBehaviour
    4. {
    5.     [SerializeField] private GameObject _soundPrefab;
    6.     private Transform _transform;
    7.     private void Awake() => _transform = transform;
    8.     public void Play(SoundEffect soundEffect)
    9.     {
    10.         GameObject soundObject = Instantiate(_soundPrefab, _transform);
    11.         AudioSource audioSource = soundObject.GetComponent<AudioSource>();
    12.         AudioClip clip = soundEffect.audioClip;
    13.         audioSource.pitch = Random.Range(soundEffect.pitchMin, soundEffect.pitchMax);
    14.         audioSource.volume = Random.Range(soundEffect.volumeMin, soundEffect.volumeMax);
    15.         audioSource.clip = clip;
    16.         audioSource.Play();
    17.         Destroy(soundObject, clip.length);
    18.     }
    19.     [System.Serializable]
    20.     public struct SoundEffect
    21.     {
    22.         public AudioClip audioClip;
    23.         public float pitchMin;
    24.         public float pitchMax;
    25.         public float volumeMin;
    26.         public float volumeMax;
    27.     }
    28. }
    29.  
    EDIT: I have made a slightly different version which adds a new audio source component instead of instantiating a prefab. Hopefully it is more efficient due to not instantiating a transform for each GameObject? Here it is anyway:

    Code (CSharp):
    1. using UnityEngine;
    2. [RequireComponent(typeof(AudioSource))]
    3. public class AudioManager : MonoBehaviour
    4. {
    5.     private GameObject _gameObject;
    6.     private void Awake() => _gameObject = gameObject;
    7.     public void Play(SoundEffect soundEffect)
    8.     {
    9.         AudioSource audioSource = _gameObject.AddComponent<AudioSource>();
    10.         audioSource.pitch = Random.Range(soundEffect.pitchMin, soundEffect.pitchMax);
    11.         audioSource.volume = Random.Range(soundEffect.volumeMin, soundEffect.volumeMax);
    12.         AudioClip clip = soundEffect.audioClip;
    13.         audioSource.clip = clip;
    14.         audioSource.Play();
    15.         Destroy(audioSource, clip.length);
    16.     }
    17.  
    18.     [System.Serializable]
    19.     public struct SoundEffect
    20.     {
    21.         public AudioClip audioClip;
    22.         public float pitchMin;
    23.         public float pitchMax;
    24.         public float volumeMin;
    25.         public float volumeMax;
    26.     }
    27. }
    28.  
    Notably it throws a warning message, presumably due to playOnAwake = true by default, therefore trying to play the empty audio clip before it is set. It still works fine, though.
     
    Last edited: Mar 24, 2022
  6. Hikiko66

    Hikiko66

    Joined:
    May 5, 2013
    Posts:
    1,304
    Code (csharp):
    1. Destroy(audioSource, clip.length);
    clip.length assumes a pitch of 1.
    If you deviate from that pitch, your time calculation is wrong.

    It should be
    Code (csharp):
    1. [Destroy(audioSource, clip.length / audioSource.pitch);
    This handles positive pitch

    To handle both positive pitch (playing forwards) and negative pitch (playing backwards) you can use this instead
    Code (csharp):
    1. Destroy(audioSource, clip.length / Math.Abs(audioSource.pitch));
    The pitch needs to not be zero though, to avoid a "divide by zero" error on this Length calculation. a Pitch of zero is a paused clip, though seeing as though clip.length is a float, even if the pitch is paused it might not throw an error most of the time due to inaccuracy with floats, but at least sometimes it would, so you will want to handle that.
     
    Last edited: Mar 24, 2022
    gamecreatorc1 and zeimhall like this.