C#
public class PlayerController : MonoBehaviour
{
    [SerializeField] AudioClip jumpClip;
    [SerializeField] float jumpVolume = 1f;
    [SerializeField] float minPitch = 0.9f;
    [SerializeField] float maxPitch = 1.1f;
    [SerializeField] float fadeInDuration = 0.5f;
    [SerializeField] float fadeOutDuration = 0.3f;

    AudioSource jumpSource;
    Coroutine activeFadeCoroutine;
    bool isFadingOut;

    void Awake()
    {
        jumpSource = GetComponent<AudioSource>();

        if (jumpSource == null)
            jumpSource = gameObject.AddComponent<AudioSource>();

        jumpSource.playOnAwake = false;
        jumpSource.loop = false;
        jumpSource.spatialBlend = 0f;
        jumpSource.volume = jumpVolume;
    }

    void OnDisable()
    {
        CancelActiveFade();
    }

    void OnJump()
    {
        PlayJumpSoundWithRandomPitchAndFadeIn();
    }

    void OnLand()
    {
        FadeOutJumpSound();
    }

    void PlayJumpSoundWithRandomPitchAndFadeIn()
    {
        if (jumpClip == null)
            return;

        if (jumpSource == null)
            return;

        CancelActiveFade();
        isFadingOut = false;

        jumpSource.Stop();
        jumpSource.clip = jumpClip;
        jumpSource.pitch = Random.Range(minPitch, maxPitch);
        jumpSource.volume = 0f;
        jumpSource.Play();

        if (fadeInDuration <= 0f)
        {
            jumpSource.volume = jumpVolume;
            return;
        }

        activeFadeCoroutine = StartCoroutine(FadeJumpVolumeIn());
    }

    void FadeOutJumpSound()
    {
        if (jumpSource == null)
            return;

        if (jumpClip == null)
            return;

        if (!jumpSource.isPlaying && !isFadingOut)
            return;

        CancelActiveFade();
        isFadingOut = true;

        if (fadeOutDuration <= 0f)
        {
            jumpSource.Stop();
            jumpSource.volume = jumpVolume;
            jumpSource.pitch = 1f;
            isFadingOut = false;
            return;
        }

        activeFadeCoroutine = StartCoroutine(FadeJumpVolumeOut());
    }

    void StopJumpSound()
    {
        CancelActiveFade();
        isFadingOut = false;

        if (jumpSource == null)
            return;

        jumpSource.Stop();
        jumpSource.volume = jumpVolume;
        jumpSource.pitch = 1f;
    }

    void CancelActiveFade()
    {
        if (activeFadeCoroutine == null)
            return;

        StopCoroutine(activeFadeCoroutine);
        activeFadeCoroutine = null;
    }

    IEnumerator FadeJumpVolumeIn()
    {
        float elapsed = 0f;
        float startVolume = jumpSource.volume;
        float targetVolume = jumpVolume;

        while (elapsed < fadeInDuration)
        {
            if (jumpSource == null)
                yield break;

            if (isFadingOut)
                yield break;

            elapsed += Time.deltaTime;
            jumpSource.volume = Mathf.Lerp(
                startVolume,
                targetVolume,
                elapsed / fadeInDuration
            );
            yield return null;
        }

        if (jumpSource == null)
            yield break;

        jumpSource.volume = targetVolume;
        activeFadeCoroutine = null;
    }

    IEnumerator FadeJumpVolumeOut()
    {
        float elapsed = 0f;
        float startVolume = jumpSource.volume;

        while (elapsed < fadeOutDuration)
        {
            if (jumpSource == null)
                yield break;

            elapsed += Time.deltaTime;
            jumpSource.volume = Mathf.Lerp(
                startVolume,
                0f,
                elapsed / fadeOutDuration
            );
            yield return null;
        }

        if (jumpSource == null)
            yield break;

        jumpSource.Stop();
        jumpSource.volume = jumpVolume;
        jumpSource.pitch = 1f;
        isFadingOut = false;
        activeFadeCoroutine = null;
    }
}