Audio cracking/popping (regardless of everything..)

Hello there

Can anyone explain the popping/cracking sounds we can here every 2 gunshots?
I recorded the issue and uploaded it on youtube:

I managed to find something that influences those cracks: testing audio clips separately.
I can say with 100% certainty the issue is coming from some of the audioclips I’m using.

Not all my audio clips have the same sample rate, I have some 44,100Hz up to 96,000Hz

However, sample rate alone isn’t the reason why this is happening since one of the working audioclips has the same sample rate as another audioclip that creates a crack…

OK, now I think I’m onto something, some of my audio clips have a single channel, others have 2. Audioclips with a single channel do not create any cracking/popping, ones with 2 do.

So, I guess my question is, why is this happening? What is the actual underlying issue?

8866890--1210242--Capture d’écran 2023-03-10 à 15.51.25.jpg

What is the audio profiler telling you? Maybe it could help highlighting a commonality between all the crackling sounds. Also what is the format of these sounds (wav, ogg, mp3, etc…)?
Lastly, and this is just a sanity check here, are you sure the clips on their own do not include the crackling sound?

I have not checked the audio profiler yet, however, I know for a fact that if I disable the low pass filters that are on all of my audiosource objects, the cracking disappears…

All files are in .WAV

Yes, I am sure they do not include any cracking
Cracking (as shown in the video) really sounds like a distortion/artefact of some sort and isn’t part of the base file

Would you be interested in seeing screenshots of the audio profiler?

I was having issues like this recently when clicking Play in the inspector preview of audio clips. The solution in my case turned out to be changing Project Settings->Audio->DSP Buffer Size from Best Latency (which I had previously set it to myself - I don’t believe it’s the default) to Good Latency.

I tried tweaking this but none of the settings I could choose from made those sounds go away, unfortunately :frowning:

I did a fair bit of reading before posting but none of the fixes worked for me and I couldn’t be sure it was the same issue since they didn’t post a video of the issue

Another thing you could try is regenerating/re-exporting the audio clips (particularly if you’re importing audio from various formats and sources), either through a batch process if you have one or for example open one in an audio editor like Audacity, create a new clip, copy/paste from the old into the new, then export fresh clip in whatever consistent format/rate/etc you want to use. Of course, doing one by one isn’t ideal, but you could do just the ones you’re using for testing to see if that helps and confirm there’s no issue with data corruption or bad info in file headers.

I’ll test re exporting them first (just a couple to start with)

Definitely zoom in with Audacity and look at the beginning and end samples, they should be right at 0. Whenever I have had popping in non-Unity projects, I have found that whatever sampling/resampling algorithms I was using had big issues with sounds starting away from 0 phase.

Ok, will look at that

I have (after reading other posts) tried to first set the volume to 0, disable the low pass filter, then destroy the object
Also do that in a coroutine and waiting for 1s before playing the sound and another second before destroying the object, didn’t help

That would be one of the file I use that has the issue:
I’m pretty sure it’s on 0 at the end and beginning

Here’s my sound object setup:

I basically spawn this at the position of where the player is shooting (end of the gun’s barrel)

Then when the sound finished playing (based on clip.length) I delete the object altogether

As I said, I tried waiting some time AFTER it finished playing, I tried setting the volume to 0 after it played, I tried disabling the high pass and low pass after it played but it didn’t have any impact

Weirdest part is it isn’t even happening every time, it’s really like 1 out of 2 times…

When the sound pops my camera is usually around 1000meters from the audio source


I have just tried to re export to different formats (ogg, wav…)
I have tried to merged the channels (stereo → mono)
Nothing helped at all, still getting the audio glitch :frowning:

I just disabled the LowPassFilter component and it works just fine without it… No popping… Anyone can explain why the low pass filter creates some noise that isn’t part of the base clip…?

If I am adjusting my low pass filter curve on the audio source, I am not getting any popping anymore
It seems to happen only when the value on the low pass filter is very low ( < 0.1 or around that value)

Alright, so if I manually set the cutOff value it’s all good… When using the Curve function that’s when things start to get weird

So, I guess I’ll just manually create my curves using the AnimationCurve, and do curve.Evaluate() and get the value from there then manually set it for the low pass filter…

Alright well I was wrong, even doing that doesn’t make the glitch go away, popping still here and strong

So, how do you guys get realistic sound without using any of the filters since they’re clearly broken… ?
How do you actually muffle sound over distance?

As incredible as this might be, as long as I am above 5000Hz for the cutoff frequency, all is fine, but if I go under this value, it starts popping all around

This is not because of my clips. There is something fundamentally wrong about how the Low Pass Filter works…

With what info should the audio profiler provide me with?
I already know it’s the low pass filter that is causing the issue

8869329--1210848--Capture d’écran 2023-03-11 à 20.18.32.jpg

Alright well I’ve tried to adjust the lowpass filter across 5 frames and that’s still producing a crack sound

Snippet of the code I used, part of a Coroutine on the object that has the audiosource:

_audioSource.Play();

if (_lowPassFilter.enabled)
{
     float startCutOff = 22000f;
     float targetCutOff = _lowPassCurve.Evaluate(_distanceToCamera) * 22000f;

     for (float i = 0; i < 5; i++)
     {
          _lowPassFilter.cutoffFrequency = Mathf.Lerp(startCutOff, targetCutOff, i / 5f);

          yield return new WaitForEndOfFrame();
     }
}

I’m done with this, Low Pass Filter is broken beyond reason

HUGE UPDATE AND SOLVED

Please, someone give this post some attention, this is a very VERY weird case

I FINALLY found out why the popping was happening

The reason why this is happening is… RIGID BODIES.
I know right?? How WEIRD

I have created a dummy soldier where I spawn my audiosource and run my code where the LowPassFilter gets assigned its curve and the volume gets its custom curve set up as well and then finally, plays the sound

Now, this dummy doesn’t have any rigidbody, and all sounds are clear, without a single cracking/popping
I can play hundreds of sounds without a single audio glitch

Now hear me out, I add a rigidbody to my dummy… Now I try again to play the sound… HAHA! Cracking and popping all over the place!

Know what’s even funnier? The rigidbody isn’t even MOVING, it’s velocity is literally ZERO

Video as proof:

Now, I demand an EXPLANATION

Full code (with dependencies on other classes, sorry):

SHOW CODE

using UnityEngine;
using System.Collections;

public class SoundEmitterGO : MonoBehaviour
{
    [Header("Setup")]
    [SerializeField] AudioSource _audioSource;

    [SerializeField] AnimationCurve _highPassCurve;
    [SerializeField] AnimationCurve _pitchCurve;

    [SerializeField] AudioLowPassFilter _lowPassFilter;
    [SerializeField] AudioHighPassFilter _highPassFilter;

    [Header("DEBUG / INFOS")]
    [SerializeField] float _distanceToCamera;
    [SerializeField] bool _destroyComponentAfterSoundPlays;
    [SerializeField] bool _usePitchCurve;
    [SerializeField] float _pitch = 1f;

    /// <summary>
    /// Starts the coroutine to play the sound delayed by distance to camera. Make sure you run the Setup() function before playing any sound.
    /// </summary>
    public void Play()
    {
        StartCoroutine(CR_PlaySound());
    }

    /// <summary>
    /// Will remove / set to null the outputAudioMixerGroup of this audiosource component
    /// </summary>
    public void DisableAudioMixer()
    {
        _audioSource.outputAudioMixerGroup = null;
    }

    /// <summary>
    /// Sets the audiosource min and max heard distance
    /// </summary>
    /// <param name="p_minDistance"></param>
    /// <param name="p_maxDistance"></param>
    public void Setup(AudioClip p_audioClip, SoundTypes p_soundType, Weapon p_weapon, bool p_destroyAfterSoundPlays)
    {
        _destroyComponentAfterSoundPlays = p_destroyAfterSoundPlays;

        _audioSource.clip = p_audioClip;

        CustomAudioSourceCurve customAudioSourceCurve = CustomAudioSourceCurve.NONE;

        switch (p_soundType)
        {
            case SoundTypes.GEAR_RATTLE:
                _audioSource.minDistance = 1.5f;
                _audioSource.maxDistance = 50f;
                _lowPassFilter.enabled = false;
                break;

            case SoundTypes.PARACHUTE_INTERACTION:
                _audioSource.minDistance = 3f;
                _audioSource.maxDistance = 50f;
                _lowPassFilter.enabled = false;
                break;

            case SoundTypes.WEAPON_RELOAD:
                _audioSource.minDistance = 1.5f;
                _audioSource.maxDistance = 50f;
                _lowPassFilter.enabled = false;
                break;

            case SoundTypes.DRY_FIRE:
                _audioSource.minDistance = 1.5f;
                _audioSource.maxDistance = 50f;
                _lowPassFilter.enabled = false;
                break;

            case SoundTypes.MELEE:
                _audioSource.minDistance = 3f;
                _audioSource.maxDistance = 15f;
                _lowPassFilter.enabled = false;
                break;

            case SoundTypes.HIT:
                _audioSource.minDistance = 1f;
                _audioSource.maxDistance = 75f;
                _lowPassFilter.enabled = false;
                break;

            case SoundTypes.BARBED_WIRE:
                _audioSource.minDistance = 1.5f;
                _audioSource.maxDistance = 50f;
                _lowPassFilter.enabled = false;
                break;

            case SoundTypes.GRENADE_COLLISION:
                _audioSource.minDistance = 1.5f;
                _audioSource.maxDistance = 75f;
                _lowPassFilter.enabled = false;
                break;

            case SoundTypes.HIT_FLESH:
                customAudioSourceCurve = CustomAudioSourceCurve.HIT_FLESH;
                _audioSource.minDistance = 1f;
                _audioSource.maxDistance = 75f;
                _lowPassFilter.enabled = false;
                break;

            case SoundTypes.MORTAR_WHISTLE:
                _audioSource.minDistance = 10f;
                _audioSource.maxDistance = 650f;
                break;

            case SoundTypes.VEHICLE_EXPLOSION:
                _audioSource.minDistance = 5f;
                _audioSource.maxDistance = 300f;
                break;

            case SoundTypes.EXPLOSION:
                if (p_weapon.Type == WeaponType.GRENADE)
                {
                    _audioSource.minDistance = 1.5f;
                    _audioSource.maxDistance = 400f;
                }
                else if (p_weapon.Type == WeaponType.MORTAR)
                {
                    _audioSource.minDistance = 3f;
                    _audioSource.maxDistance = 850f;
                }
                else
                {
                    _usePitchCurve = true;
                    customAudioSourceCurve = CustomAudioSourceCurve.EXPLOSION;
                    _audioSource.minDistance = 10f;
                    _audioSource.maxDistance = 2000f;
                }
                break;

            case SoundTypes.SHOOT:
                if (p_weapon.Type == WeaponType.GUN)
                {
                    customAudioSourceCurve = CustomAudioSourceCurve.GUN;
                    _audioSource.minDistance = 3f;
                    _audioSource.maxDistance = 1500f;
                }
                else if (p_weapon.Type == WeaponType.HIGH_CALIBER_MG)
                {
                    _usePitchCurve = true;
                    customAudioSourceCurve = CustomAudioSourceCurve.HIGH_CALIBER;
                    _audioSource.minDistance = 1.3f;
                    _audioSource.maxDistance = 1500f;
                }
                else if (p_weapon.Type == WeaponType.SMALL_ARM)
                {
                    _usePitchCurve = true;
                    _highPassFilter.enabled = true;
                    customAudioSourceCurve = CustomAudioSourceCurve.SMALL_ARM;
                    _audioSource.minDistance = 1.3f;
                    _audioSource.maxDistance = 1500f;
                }
                else if (p_weapon.Type == WeaponType.ROCKET)
                {
                    customAudioSourceCurve = CustomAudioSourceCurve.ROCKET;
                    _audioSource.minDistance = 5f;
                    _audioSource.maxDistance = 2000f;
                }
                else if (p_weapon.Type == WeaponType.ROCKET_LAUNCHER)
                {
                    _lowPassFilter.enabled = false;
                    customAudioSourceCurve = CustomAudioSourceCurve.ROCKET_LAUNCHER;
                    _audioSource.minDistance = 1f;
                    _audioSource.maxDistance = 100f;
                }
                break;
        }

        SetCurves(customAudioSourceCurve);
    }

    void SetCurves(CustomAudioSourceCurve p_shotWeaponType)
    {
        _audioSource.rolloffMode = AudioRolloffMode.Custom;

        // Setting up High Pass filter
        if (_highPassFilter.enabled)
        {
            _highPassCurve.keys = null;
            _highPassCurve.AddKey(300f, 10f);
            _highPassCurve.AddKey(_audioSource.maxDistance, 2000f);
        }

        if (_lowPassFilter.enabled)
        {
            AnimationCurve curve = new AnimationCurve();
            curve.AddKey(_audioSource.minDistance, 1f);

            if (p_shotWeaponType == CustomAudioSourceCurve.SMALL_ARM || p_shotWeaponType == CustomAudioSourceCurve.HIGH_CALIBER)
            {
                curve.AddKey(_audioSource.maxDistance / 10.7f, 0.35f);
                curve.AddKey(_audioSource.maxDistance / 7.3f, 0.2f);
                curve.AddKey(_audioSource.maxDistance / 5.15f, 0.11f);
                curve.AddKey(_audioSource.maxDistance / 3.7f, 0.08f);
                curve.AddKey(_audioSource.maxDistance / 1.5f, 0.04f);
                curve.AddKey(_audioSource.maxDistance, 0.02f);
            }
            else
            {
                curve.AddKey(_audioSource.maxDistance / 10f, 0.35f);
                curve.AddKey(_audioSource.maxDistance / 4.5f, 0.16f);
                curve.AddKey(_audioSource.maxDistance / 2f, 0.04f);
                curve.AddKey(_audioSource.maxDistance / 1.5f, 0.02f);
                curve.AddKey(_audioSource.maxDistance, 0f);
            }

            _lowPassFilter.customCutoffCurve = curve;
        }

        AnimationCurve audioSourceCurve = new AnimationCurve();
        audioSourceCurve.AddKey(_audioSource.minDistance, 1f);

        switch (p_shotWeaponType)
        {
            case CustomAudioSourceCurve.HIT_FLESH:
                audioSourceCurve.AddKey(_audioSource.maxDistance / 10f, 0.5f);
                audioSourceCurve.AddKey(_audioSource.maxDistance / 3, 0.1f);
                break;

            case CustomAudioSourceCurve.SMALL_ARM:
                audioSourceCurve.AddKey(_audioSource.maxDistance / 100f, 0.5f);
                audioSourceCurve.AddKey(_audioSource.maxDistance / 50f, 0.35f);
                audioSourceCurve.AddKey(_audioSource.maxDistance / 19f, 0.19245f);
                audioSourceCurve.AddKey(_audioSource.maxDistance / 8.5f, 0.1f);
                audioSourceCurve.AddKey(_audioSource.maxDistance / 3f, 0.05f);
                audioSourceCurve.AddKey(_audioSource.maxDistance / 2f, 0.04f);
                audioSourceCurve.AddKey(_audioSource.maxDistance / 1.5f, 0.03f);
                audioSourceCurve.AddKey(_audioSource.maxDistance, 0);
                break;

            case CustomAudioSourceCurve.HIGH_CALIBER:
                audioSourceCurve.AddKey(_audioSource.maxDistance / 100f, 0.5f);
                audioSourceCurve.AddKey(_audioSource.maxDistance / 50f, 0.35f);
                audioSourceCurve.AddKey(_audioSource.maxDistance / 19f, 0.19245f);
                audioSourceCurve.AddKey(_audioSource.maxDistance / 8.5f, 0.1f);
                audioSourceCurve.AddKey(_audioSource.maxDistance / 3f, 0.05f);
                audioSourceCurve.AddKey(_audioSource.maxDistance / 2f, 0.04f);
                audioSourceCurve.AddKey(_audioSource.maxDistance / 1.5f, 0.03f);
                break;

            case CustomAudioSourceCurve.GUN:
                audioSourceCurve.AddKey(_audioSource.maxDistance / 40f, 0.6f);
                audioSourceCurve.AddKey(_audioSource.maxDistance / 20f, 0.3f);
                audioSourceCurve.AddKey(_audioSource.maxDistance / 6.3f, 0.1f);
                audioSourceCurve.AddKey(_audioSource.maxDistance / 3f, 0.045f);
                audioSourceCurve.AddKey(_audioSource.maxDistance / 1.33f, 0.025f);
                break;

            case CustomAudioSourceCurve.ROCKET:
                audioSourceCurve.AddKey(_audioSource.maxDistance / 40f, 0.6f);
                audioSourceCurve.AddKey(_audioSource.maxDistance / 20f, 0.3f);
                audioSourceCurve.AddKey(_audioSource.maxDistance / 6.3f, 0.1f);
                audioSourceCurve.AddKey(_audioSource.maxDistance / 3f, 0.045f);
                audioSourceCurve.AddKey(_audioSource.maxDistance / 1.33f, 0.025f);
                break;

            case CustomAudioSourceCurve.ROCKET_LAUNCHER:
                audioSourceCurve.AddKey(_audioSource.maxDistance / 10f, 0.35f);
                audioSourceCurve.AddKey(_audioSource.maxDistance / 4f, 0.1f);
                audioSourceCurve.AddKey(_audioSource.maxDistance / 3f, 0.05f);
                audioSourceCurve.AddKey(_audioSource.maxDistance / 1.5f, 0.015f);
                break;

            case CustomAudioSourceCurve.EXPLOSION:
                audioSourceCurve.AddKey(_audioSource.maxDistance / 16f, 0.5f);
                audioSourceCurve.AddKey(_audioSource.maxDistance / 5f, 0.15f);
                audioSourceCurve.AddKey(_audioSource.maxDistance / 2.85f, 0.05f);
                break;

            default:
                audioSourceCurve.AddKey(_audioSource.maxDistance / 30f, 0.5f);
                audioSourceCurve.AddKey(_audioSource.maxDistance / 10f, 0.15f);
                audioSourceCurve.AddKey(_audioSource.maxDistance / 5f, 0.1f);
                break;
        }

        audioSourceCurve.AddKey(_audioSource.maxDistance, 0f);

        _audioSource.SetCustomCurve(AudioSourceCurveType.CustomRolloff, audioSourceCurve);
    }

    /// <summary>
    /// Delays the play of the sound by the time it would take the sound to reach the camera
    /// </summary>
    /// <param name="p_audioClip"></param>
    /// <returns></returns>
    IEnumerator CR_PlaySound()
    {
        _distanceToCamera = Vector3.Distance(this.transform.position, CameraGO.instance.transform.position);

        yield return new WaitForSeconds(_distanceToCamera / StaticClass.SPEED_OF_SOUND);

        if (_distanceToCamera <= _audioSource.maxDistance)
        {
            if (_distanceToCamera <= _audioSource.minDistance) _lowPassFilter.enabled = false; // Unity bug, even if within minimum distance and max low pass value, sound gets cropped somehow...
            if (_highPassFilter.enabled) _highPassFilter.cutoffFrequency = _highPassCurve.Evaluate(_distanceToCamera);
            if (_usePitchCurve) _pitch = _pitchCurve.Evaluate(_distanceToCamera / _audioSource.maxDistance);

            _audioSource.pitch = _pitch;

            _audioSource.Play();
        }

        if (_destroyComponentAfterSoundPlays) Destroy(this.gameObject, _audioSource.clip.length);
    }
}