SEAMLESS LOOPING VEHICLE & ENGINE AUDIO IN UNITY

Eliminate loop clicks, popping artifacts, and repetitive drone by blending multi-track idle, low, medium, and high RPM audio layers in C#.

1. The Zero-Crossing Rule for Seamless Loops

Audible clicks at audio loop points occur when an audio waveform cuts off abruptly at a non-zero amplitude before jumping back to the start. The speaker cone is forced to instantaneously jump position, producing a sharp electrical "pop".

In Audacity or any DAW, ensure your sample loop start and end points align precisely at zero-crossing points (where the waveform crosses 0 dB) and apply a gentle 3-5ms crossfade.

2. Multi-Layer Engine Audio Crossfader Script

Rather than stretching a single audio clip across extreme pitch ranges (which sounds artificial), high-end games like Operation Black Sky use two overlapping AudioSources that crossfade between Idle and Full Throttle:

using UnityEngine;

/// <summary>
/// Crossfades between Idle and High-RPM engine loops with dynamic pitch modulation.
/// </summary>
public class EngineAudioCrossfader : MonoBehaviour
{
    [Header("Audio Sources")]
    [SerializeField] private AudioSource idleSource;
    [SerializeField] private AudioSource highRpmSource;

    [Header("Vehicle Reference")]
    [SerializeField] private Rigidbody vehicleRb;
    [SerializeField] private float topSpeed = 60f; // in m/s

    [Header("Pitch Bounds")]
    [SerializeField] private float minPitch = 0.8f;
    [SerializeField] private float maxPitch = 1.6f;

    private void Start()
    {
        // Configure both audio sources to loop seamlessly
        idleSource.loop = true;
        highRpmSource.loop = true;

        idleSource.Play();
        highRpmSource.Play();
    }

    private void Update()
    {
        if (vehicleRb == null) return;

        // Calculate normalized speed ratio [0.0 to 1.0]
        float currentSpeed = vehicleRb.velocity.magnitude;
        float speedRatio = Mathf.Clamp01(currentSpeed / topSpeed);

        // 1. Crossfade Volumes
        idleSource.volume = Mathf.Lerp(1.0f, 0.1f, speedRatio);
        highRpmSource.volume = Mathf.Lerp(0.0f, 1.0f, speedRatio);

        // 2. Modulate Pitch with Throttle Load
        float calculatedPitch = Mathf.Lerp(minPitch, maxPitch, speedRatio);
        idleSource.pitch = calculatedPitch;
        highRpmSource.pitch = calculatedPitch;
    }
}

Related Guides & Tools

Frequently Asked Questions

Use PCM (Uncompressed) or Vorbis (Quality 70-80%) with Decompress On Load selected in Unity's Audio Clip import settings. Streaming compressed audio from disk can cause micro-buffer underruns during loop boundaries on mobile devices.
Add a third AudioSource with a heavy low-frequency rumble clip that only fades in when the player presses the Boost key (Input.GetKey(KeyCode.LeftShift)), accompanied by screen shake and a slight camera FOV expansion.