Vehicle Noise Synthesizer

ATG Simulator Developer Reference v1.9

Overview

Vehicle Noise Synthesizer (VNS) is a Unity granulator-style engine audio component (package menu: ATG Audio / Vehicle Noise Synthesizer). It blends real recorded clips at known RPM values using a constant-power neighbour-pair crossfade, driven by rpm and load each physics fixed step.

The active pair is selected with RPM hysteresis and combustion-cycle hold (tick-quantized). Per-clip pitch uses an RPM-ratio model with optional stretch soft-clamp. Non-WebGL builds batch every active instance in a Burst IJobParallelFor once per Time.fixedTimeAsDouble step and complete the same tick. WebGL runs the same algorithm on the main thread in ProcessAudioFrame.

Key Features (v1.9)

  • RPM-ratio pitch: (pitchRpm / clip.referenceRpm) × finalPitch, then loPitch/hiPitch multipliers, bank trim, and clip pitch offset. Final pitch is clamped to 0.01…3 (Unity clip pitch limit).
  • maxPitchRatioBeyondPair (default 1.2): soft-clamps the RPM used for pitch and can escape a pair hold when live RPM leaves the pair window far enough.
  • Burst batch path (non-WebGL) and WebGL main-thread path with matching pair/pitch logic.
  • Immediate spectral load via raw filterLoad for LPF/HPF/distortion (and reverb load term). Bank volume and acc/dec blend still use smoothedLoad.
  • Constant-power crossfade between the two active neighbour clips (cos² + sin² = 1).
  • Three-tier pitch control: pitchCurve, bank acPitchTrim/dcPitchTrim, per-clip loPitch/hiPitch.
  • Event-driven one-shots: OnThrottleTipIn, OnThrottleTipOut, OnGearShift (throttle body + DCT shift burble).
  • Exhaust burble (load window + optional RPM-drop path) and redline one-shot loop. Engine lugging is not present in this package.
  • Editor Simple / Advanced inspector mode (EditorPrefs only; does not change runtime).
  • NWH VP2 sample: AudioGranulatorNWHVehiclePhysics2 with optional disableNwhEngineRunningAudio and EnginePitchOscillator writing shiftPitchOsc.

What's New through v1.9 v1.9

This page documents the current public package behavior.

Pitch & neighbour pairs

  • Per-clip pitch uses loPitch/hiPitch multipliers (default 1.0, range 0.01-3), not absolute 0.5-2.5 clamps.
  • Final layer pitch is clamped to 0.01f…3f (matches Unity AudioSource.pitch for clips).
  • maxPitchRatioBeyondPair (default 1.2, range 1-2): soft-clamps the RPM used for pitch into the active pair window ±stretch, and can escape pair hold when RPM leaves that window.
  • Pair hold (pairHoldCycles, default 0.5) is quantized up to whole fixedDeltaTime ticks. Switch jumps to the ideal neighbour pair when hysteresis or stretch-escape allows (no one-step crawl in this package).
  • Removed / absent APIs from older docs: rpmPitchTracking, absolute min/max pitch fields as clamps, commented-out idlePitch, engine lugging (not present).

Burst / WebGL & GC

  • Non-WebGL: one Burst batch per fixed step via fixedTimeAsDouble, same-tick complete, rebuild fallthrough, dispose on last unregister, dirty curve uploads.
  • WebGL: ProcessAudioFrame on the main thread.
  • Nested Mathf.Max on hot RPM paths (avoids 3-arg params alloc). Cached WaitForFixedUpdate.

Load → spectrum (v1.9)

  • Raw filterLoad drives LPF curve, HPF load scale, distortion load term, and reverb load term.
  • LPF/HPF cutoffs and Q (and distortion level) are applied immediately each fixed tick (legacy filterLPFSlewHz/filterHPFSlewHz do not slew bank cutoffs).
  • Bank volume, acc/dec blend, and pitch load trim still use smoothedLoad / loadResponseTime.

Events, one-shots, editor, NWH sample

  • OnThrottleTipIn / OnThrottleTipOut / OnGearShift are the only triggers for throttle-body and DCT shift effects (no internal load-delta auto-detect).
  • Burble uses burbleLoadLowThreshold + burbleLoadHighThreshold (load window) and optional RPM-drop path.
  • Redline one-shot loop while RPM stays in redlineMinRPMredlineMaxRPM (0 max = use maxRpm).
  • Editor toolbar Simple | Advanced (EditorPrefs key VNS_InspectorAdvancedMode).
  • NWH sample: disableNwhEngineRunningAudio (default true); oscillator uses fixedDeltaTime, seeds baseline RPM, caps gear intensity at 1.0 (no revLimiterThreshold multiplier in current sample).

The 3-Tier Pitch Guide

Pitch is the single most common thing you will tune. VNS gives you three levels of control, from the broadest brush to the finest. Always reach for the broadest tier that solves your problem.

Tier 1 - Global Curve

Everything, both banks

If every clip (acceleration and deceleration alike) sounds too high or too low, shape the global pitchCurve. The default is a flat constant 1.0.

Field: pitchCurve (AnimationCurve)
Section: Global Curves
Tier 2 - Per-Bank

All accel OR all decel

If the whole acceleration bank, or the whole deceleration bank, is off relative to the other, trim that one bank.

Fields: acPitchTrim / dcPitchTrim
Section: Tuning
Tier 3 - Per-Clip

One clip at a time

If a single clip is higher or lower than its neighbours, adjust its own loPitch/hiPitch multipliers with the blue Lo/Hi bar under its clip row.

Fields: loPitch (Lo) / hiPitch (Hi)
Section: Acceleration / Deceleration Bank

How the per-clip Lo / Hi window works

Each clip has two pitch multiplier fields shown on the blue bar beneath its audio-clip field:

  • Lo (loPitch) is the multiplier applied to the RPM-ratio pitch at the lowest RPM of this clip's active range (just after it fades in). Default 1.0 = neutral.
  • Hi (hiPitch) is the multiplier applied to the RPM-ratio pitch at the highest RPM of its range (just before the next clip takes over). Default 1.0 = neutral.

Runtime pitch (from source) for an active layer, simplified:

  1. finalPitch = max(0.01, pitchCurve(normRpm) + loadEffectivenessOnPitch × smoothedLoad + shiftPitchOsc)
  2. pitchRpm is live RPM soft-clamped into the active pair window using maxPitchRatioBeyondPair.
  3. ratioPitch = (pitchRpm / max(1, clip.referenceRpm)) × finalPitch
  4. progress = Clamp01((pitchRpm - idleRpm) / max(1, maxRpm - idleRpm))
  5. pitch = Clamp(ratioPitch × Lerp(loPitch, hiPitch, progress) + bankPitchTrim + pitchOffset, 0.01, 3)

Lo and Hi interpolate as RPM progresses through idle…max. The inspector Lo/Hi bar uses the real clip pitch scale 0.01…3 (not 0…4).

Lo and Hi default to 1.0 = fully automatic. When both are 1.0, the RPM-ratio pitch model (engineRPM / clipRPM) runs unmodified - the engine sounds physically correct with zero per-clip tuning, provided your audio clips are well-recorded and rpmValue is accurate. Lo/Hi are artistic fine-tuning controls only: reach for them when a single clip sounds slightly too high or too low relative to its neighbours, not as a substitute for correct rpmValue assignment.

Recommended Quick-Start Recipe

This neutralizes every pitch tier first, then lets your ears do the work. It produces surprisingly realistic results fast.

  1. Set the pitchCurve (Global Curves) to a flat constant 1.0 (the default).
  2. Set every clip's Lo and Hi values to 1.0 (neutral). With correct rpmValue and well-recorded clips, the RPM-ratio model produces realistic pitch automatically. Only adjust Lo/Hi later if a specific clip sounds out of place relative to its neighbours - these are artistic fine-tuning controls, not required tuning.
  3. Set acPitchTrim and dcPitchTrim (Tuning) to 0.
  4. Before anything else, assign the correct rpmValue to every clip in the banks. This is the single most important data point - the entire RPM-ratio model depends on it.
  5. Enable debug, then sweep debugrpm across the range and listen. Adjust by ear, starting from the broadest tier that helps.
Your audio clips and their RPM values directly shape the end result. No parameter can rescue badly recorded or badly spaced clips, so invest in good, seamless loops first.

Setup & Usage

ATG Simulator note: The project already includes NWH Vehicle Physics 2. The bridge script AudioGranulatorNWHVehiclePhysics2.cs automatically feeds NWH engine data into VNS, so no manual wiring is required.

Requirements

  • Unity 2021.3 or newer.
  • Unity.Mathematics and Unity.Burst packages (install via Package Manager).
  • NWH Vehicle Physics 2 (included in the ATG Simulator project).

Adding VNS to a Vehicle

  1. Add the VehicleNoiseSynthesizer component to your vehicle's audio root GameObject (menu: "ATG Audio / Vehicle Noise Synthesizer").
  2. Assign an AudioSource to audioSourceTemplate. The pooling system copies its 3D settings for every generated source.
  3. Populate acceleratingSounds with your clips. For each, set the AudioClip and the rpmValue it was recorded at. The rpmValue field is a plain integer text box in v1.9f - type exact values.
  4. Set each clip's loPitch and hiPitch multipliers (default 1.0 = neutral). Watch the active-pair volume graph confirm your blends.
  5. Add the matching bridge from Scripts/Inputs/NWH-Physics_IntegrationSample.

Debugging with the Simple UI

The sample scene plus AudioGranulatorSimpleUI gives sliders and keyboard controls (Up/Down for RPM, Left/Right for Load) to audition sounds without a full vehicle. It supports both the New Input System and the Legacy Input Manager.

Live Inspector Simulator

A faithful, fully interactive recreation of the VehicleNoiseSynthesizer inspector. Every section opens with a plain-language explainer of what it does, and hovering (or tapping ) any field reveals its documentation tooltip with type, range, and a practical tip. Drag the master Debug RPM scrubber to watch the blend graphs and the active-clip pair update live.

How to read it: Coloured dots mark pitch tiers - ● Global, ● Per-Bank, ● Per-Clip. Hit Expand all, then sweep Debug RPM to see exactly which two clips blend at any moment.

Vehicle Noise Synthesizer (Script)
v1.9 • github.com/ImDanOush/VehicleNoiseSynthesizer

Full Parameter Reference

Every public field on VehicleNoiseSynthesizer, grouped as in the inspector. Defaults and ranges match VehicleNoiseSynthesizer.cs (v1.9 source).

Debug Controls

  • debug (bool, default false):

    Enable to manually control RPM and load values for testing. When true, the fixed-step loop uses debugrpm / debugload instead of _rpm / _load.

  • enablePairSelectorDiagnostics (bool, default false):

    Pair-selector diagnostic logger (hold duration, hysteresis, switches once per second).

  • debugrpm (float, 100-9000, default 800):

    Test RPM value when debug mode is enabled.

  • debugload (float, 0-1, default 1):

    Test engine load when debug is enabled. Also becomes the raw filterLoad used by LPF/HPF/distortion.

  • enableDiagnosticLogger (bool, default false):

    Enable the 1-second diagnostic logger.

  • enableBurbleDiagnostics (bool, default false):

    Enable burble gate diagnostics in the console.

Core

  • audioSourceTemplate (AudioSource):

    Template the pooling system clones for every generated voice. Its 3D settings (spatial blend, rolloff) are copied to all sources.

  • mixer (AudioMixerGroup):

    Optional mixer group for routing.

  • mixerType (enum):

    Role label: Intake, Engine, Exhaust, Transmission, or Differential.

  • masterVolume (float, 0.007-1.00, default 1):

    Master volume for all engine sounds.

  • autoBlip (bool, default true):

    Forces the acceleration bank blend to 1.0 on a sharp RPM jump.

  • rpmdeviation (int, default 1000):

    Fallback RPM spacing used when neighbouring clips are missing.

  • shiftPitchOsc (float, HideInInspector):

    Gear-change pitch oscillation value written by the NWH bridge (AudioGranulatorNWHVehiclePhysics2). Not shown in the inspector; driven automatically.

Global Curves

  • pitchCurve (AnimationCurve) Pitch Tier 1:

    Global pitch contour vs normalized RPM. Default is a flat constant 1.0. Keep flat while tuning, then add character later. The curve value is multiplied into every clip's RPM-ratio pitch.

  • volumeCurve (AnimationCurve):

    Bank loudness vs normalized RPM. Default rises from 0.5 to 1.0.

  • loadEffectivenessOnPitch (float, default 0.05):

    How much engine load bends the global pitch contour.

Volume Configuration

  • idleVolume (float, 0.05-1.00, default 0.1):

    Default volume when the engine is at idle.

  • maxVolumeAcc (float, 0-2, default 0.4):

    Volume cap for acceleration sounds (0 = no limit). Values above 1.0 boost the bank.

  • maxVolumeDcc (float, 0-2, default 0.1):

    Volume cap for deceleration sounds (0 = no limit).

Blend Behaviour

  • keepBankClipsPlaying (bool, default true):

    Keep silent clips looping at zero volume to avoid playback-start latency.

  • clipVolumeResponseTime (float, 0.005-0.50, default 0.05):

    Per-layer volume smoothing time in seconds.

  • clipPitchResponseTime (float, 0.005-0.50, default 0.04):

    Per-layer pitch smoothing time in seconds.

  • rpmResponseTime (float, 0.005-0.50, default 0.035):

    Input RPM smoothing time in seconds.

  • loadResponseTime (float, 0.005-0.50, default 0.04):

    Input load smoothing time in seconds.

  • pairHysteresisRpm (float, 0-500, default 120):

    Extra RPM margin required before the active clip pair is allowed to switch.

  • pairHoldCycles (float, 0-20, default 0.5):

    Minimum hold after a pair switch, in combustion-event cycles. Raw duration is rounded up to whole fixedDeltaTime ticks. 0 disables the hold (pairHysteresisRpm still applies). High values can cause pitch stretch if RPM races ahead of the held pair.

  • maxPitchRatioBeyondPair (float, 1-2, default 1.2):

    How far live RPM may go past the active pair outer reference before pitch is soft-clamped and hold can escape (1.2 = ±20%). Prevents chipmunk pitch during pair catch-up.

Acc/Dec Crossfade

  • loadCrossoverPoint (float, 0-0.5, default 0.18):

    Load value where acceleration and deceleration banks blend 50/50.

  • loadBlendWidth (float, 0.01-0.4, default 0.10):

    Width of the blend zone around the crossover point.

  • loadVolumeAccChangerFactor (float, 0-1, default 1):

    Depth of load-based volume modulation for the accel bank.

  • loadVolumeDccChangerFactor (float, 0-1, default 1):

    Depth of load-based volume modulation for the decel bank.

  • loadVolumeChangerMinValue (float, 0-0.99, default 0.1):

    Gain floor at the weakest load state.

Combustion Timing

  • cylinderCount (int, 1-16, default 4):

    Cylinder count used to estimate firing frequency. This is the v1.8 "magic" that makes the blend a granular, looped system, repeating clips per the engine's cylinder spec for realism.

  • combustionCycleMode (enum, default FourStroke):

    FourStroke uses cylinderCount/2 firing events per revolution; TwoStroke uses cylinderCount.

Acceleration / Deceleration Banks

  • acceleratingSounds (List<EngineAudioClipData>:

    List of audio clips for engine acceleration.

  • deceleratingSounds List<EngineAudioClipData>:

    Optional list of audio clips for engine deceleration. If empty or null after strip, runtime sets nonDecelerateAudiosMode and reuses the acceleration bank for both directions.

Each clip is an EngineAudioClipData:

  • audioClip (AudioClip):

    The recorded engine sound.

  • rpmValue (int, 0-10000, default 1000):

    RPM the clip was recorded at. Plain integer field in v1.9f (no slider). This is the foundation of the RPM-ratio pitch model.

  • description (string):

    Optional description for this audio clip.

  • loPitch (float, 0.01-3, default 1) Pitch Tier 3:

    Low-end pitch multiplier at minimum RPM (1 = neutral). [Range(0.01f, 3f)] matches runtime pitch clamp.

  • hiPitch (float, 0.01-3, default 1) Pitch Tier 3:

    High-end pitch multiplier at maximum RPM (1 = neutral). [Range(0.01f, 3f)].

  • volumeOffset (float, -1 to 1, default 0):

    Per-clip volume trim.

  • pitchOffset (float, -0.5 to 0.5, default 0):

    Per-clip pitch trim added to the final computed pitch.

Tuning

  • acPitchTrim (float, -1 to 1, default 0) Pitch Tier 2:

    Pitch trim for the entire acceleration bank.

  • dcPitchTrim (float, -1 to 1, default 0) Pitch Tier 2:

    Pitch trim for the entire deceleration bank.

  • maximumTheoricalRPM (float, 1000-20000, default 10000):

    Maximum theoretical RPM used for normalization and graph scaling.

  • lowPassStrength (float, 0-1, default 0):

    Low-pass muffling boost.

  • highPassStrength (float, 0-1, default 0):

    High-pass rasp strength.

  • resonanceStrength (float, 0-1, default 0):

    Resonance strength.

  • distortionStrength (float, 0-1, default 0):

    Distortion boost multiplier.

  • chorusStrength (float, 0-1, default 0):

    Chorus strength.

  • reverbStrength (float, 0-1, default 0):

    Reverb strength.

  • useSharedMixerReverb (bool, default true):

    When true, per-layer AudioReverbFilter components are NOT created; reverb is routed through the mixer instead.

  • reverbMixerParamName (string, default "ReverbAmount"):

    Name of the exposed float parameter on the mixer that controls reverb send/wet level. Only used when useSharedMixerReverb is true.

FX Curves & Sound Character

Optional artistic effects driven by RPM and load. All use Unity's native audio filters.

  • distortionCurve (AnimationCurve):

    Controls distortion amount based on RPM and load.

  • distortionIntensity (float, 0-1, default 0.5):

    Overall intensity of the distortion effect. Target uses filterLoad; level is assigned immediately each fixed tick.

  • mufflingIntensity (float, 0-1, default 0.5):

    Intensity of the muffling effect when engine load decreases.

  • lowPassCurve (AnimationCurve):

    Controls low-pass frequency cutoff based on engine load. Default 800 Hz at load 0, 22000 Hz at load 1.

  • lowPassIntensity (float, 0-1, default 0.5):

    Overall intensity of the low pass filter effect. Cutoff snaps with filterLoad each fixed tick.

  • filterLPFSlewHz (float, 100-5000, default 800):

    Legacy. LPF cutoff snaps with load each tick; not used for bank cutoff.

  • filterHPFSlewHz (float, 10-500, default 180):

    Legacy. HPF cutoff snaps with load each tick; not used for bank cutoff.

  • filterReverbSlewDbS (float, 500-5000, default 2500):

    Max dB/s the reverb level may move.

  • filterParamSlewRate (float, 0.1-5, default 1):

    Slew multiplier for MoveTowards on chorus. LPF/HPF/distortion are snapped.

Throttle Body Configuration v1.9

  • enableThrottleBody (bool, default true):

    Enable throttle body sounds: intake roar on tip-in, flutter on tip-out.

  • intakeRoarSounds (AudioClip[]):

    Audio clips played as a one-shot when the throttle snaps open (tip-in / intake roar).

  • throttleFlutterSounds (AudioClip[]):

    Audio clips played as a one-shot when the throttle snaps shut at high RPM (tip-out / flutter).

  • intakeRoarVolume (float, 0-1, default 0.6):

    Master volume for intake roar. Runtime: intakeRoarVolume × throttleValue × Max(0.5, engineLoad).

  • throttleFlutterVolume (float, 0-1, default 0.5):

    Master volume for throttle flutter clips.

  • throttleBodyPitchVariation (float, 0-0.3, default 0.05):

    Random ±pitch variation applied to each throttle body one-shot.

  • throttleBodyCooldown (float, 0.01-1, default 0.08):

    Minimum seconds between successive throttle body triggers (prevents spamming).

Exhaust Redline Configuration v1.9

  • enableRedlineEffect (bool, default true):

    Enable the exhaust crackle/pressure-wave sound that repeats while the engine is held near redline.

  • redlineSounds (AudioClip[]):

    Audio clips played in a repeating loop while RPM stays within the redline range.

  • redlineVolume (float, 0-1, default 0.6):

    Master volume for redline exhaust clips.

  • redlineMinRPM (float, default 7000):

    RPM at which the redline effect begins to trigger.

  • redlineMaxRPM (float, default 0):

    RPM ceiling for the redline effect (0 = no upper limit, uses maxRpm).

  • redlineMinDelay (float, 0.01-1, default 0.05):

    Minimum delay (seconds) between successive redline one-shot clips.

  • redlineMaxDelay (float, 0.01-2, default 0.2):

    Maximum delay (seconds) between successive redline one-shot clips.

  • redlineBasePitch (float, 0.5-2, default 1):

    Base pitch for redline clips.

  • redlinePitchVariation (float, 0-0.3, default 0.05):

    Random ±pitch variation per redline clip.

Exhaust Burble & DCT Shift Burble

  • enableExhaustBurble (bool, default true) + burbleSounds, burbleVolume (0-1, default 0.7), burbleMinRPM (default 3500), burbleLoadLowThreshold (0-1, default 0.0), burbleLoadHighThreshold (0-1, default 0.3), burbleRPMDropThreshold (0-3000, default 500), burbleProbability (0-1, default 0.7), minBurbleDelay (0.01-0.5, default 0.05), maxBurbleDelay (0.05-1, default 0.2), burbleRandomPitchVariation (0-0.2, default 0.08), burbleFadeRate (4-100, default 40):

    Overrun pops. Eligible when RPM ≥ min and load is in [burbleLoadLowThreshold, burbleLoadHighThreshold) or RPM drop ≥ burbleRPMDropThreshold (if > 0). Uses smoothedLoad for the load gate.

  • enableDctShiftBurble (bool, default true) + dctShiftBurbleSound (AudioClip), dctShiftBurbleVolume (0-1, default 0.7), dctShiftBurbleRpmVolumeInfluence (0-1, default 0.5), dctShiftBurbleMinRPM (default 2000), dctShiftBurbleMaxDuration (0.01-1, default 0.12), dctShiftBurbleBasePitch (0.5-2, default 1), dctShiftBurblePitchVariation (0-0.3, default 0.05):

    Looping exhaust overlay fired only via OnGearShift(). Pitch clamped to 0.01-3. After a short grace period, a raw-load tip-in can start fade-out.

Internal / Hidden Fields

  • launchMode (bool, HideInInspector, default false):

    Forces full acceleration blend. Used programmatically for launch control sequences.

  • nonDecelerateAudiosMode (private bool):

    Automatically set to true when the deceleration bank is empty. Causes the accel bank to be reused for both directions through the load crossover.

Public Event API v1.9f+

Integration scripts must call these three methods at the appropriate moments. The old deltaLoad-based auto-detection in UpdateThrottleBodyEffects and UpdateDctShiftBurble has been removed - these effects will not play unless an integration script calls the corresponding method.

OnThrottleTipIn(float throttleValue, float rpm, float engineLoad)

Call when the player's throttle input jumps from near-zero to near-full (0→1 tip-in). Plays a one-shot intake roar clip.

  • Guards: enableThrottleBody must be true; _isOn must be true (engine running); cooldown must be elapsed.
  • Volume: intakeRoarVolume × throttleValue × Max(0.5, engineLoad) (from OnThrottleTipIn source). Engine must be on (isOn).
  • Pitch: slight upward scaling with normalised RPM.

OnThrottleTipOut(float rpm, float engineLoad)

Call when the player's throttle input drops from near-full to near-zero (1→0 tip-out). Plays a one-shot throttle flutter clip.

  • Guards: enableThrottleBody must be true; _isOn must be true; cooldown must be elapsed.
  • Volume: throttleFlutterVolume (constant - flutter is a release sound).
  • Pitch: slight upward scaling with normalised RPM.

OnGearShift()

Call when the transmission changes gear. Fires the DCT shift burble (looping exhaust overlay).

  • Guards: enableDctShiftBurble must be true; dctShiftBurbleSound must be assigned.
  • Duration: plays for up to dctShiftBurbleMaxDuration (default 0.12s).
  • Cut-off: stops immediately if engine load increases (driver floors it), but only after a 30ms grace period to ignore transmission-engagement noise.

NWH Vehicle Physics 2 Integration

ATG Simulator uses NWH Vehicle Physics 2. The bridge script feeds engine data straight into VNS.

AudioGranulatorNWHVehiclePhysics2

  • Hooks the engine's onStart/onStop events to call TurnOn()/TurnOff().
  • Each FixedUpdate passes engine.OutputRPM to rpm and engine.Load to load.
  • Throttle tracking: Tracks vp.input.Throttle across ticks. When throttle jumps 0→1 (below 0.2 to above 0.8), calls OnThrottleTipIn(throttle, rpm, engineLoad). When it drops 1→0, calls OnThrottleTipOut(rpm, engineLoad). The 0.2/0.8 hysteresis bands prevent noise at transition boundaries.
  • Detects gear changes, drives the EnginePitchOscillator (writing to shiftPitchOsc), and calls OnGearShift() to fire the DCT shift burble.

⚠️ If using a custom input script: You must call OnThrottleTipIn, OnThrottleTipOut, and OnGearShift at the appropriate moments, or the throttle body and DCT shift burble effects will never play.

EnginePitchOscillator (sample defaults)

  • oscillationSpeed (8) / oscillationDepth (0.15)
  • rpmIncreaseThreshold (150) / rpmDecreaseThreshold (80) - no revLimiterThreshold in current sample
  • dampingFactor (5) / loadInfluence (0.3) / effectDelay (0.05)
  • harmonicFrequency (2) / harmonicAmplitude (0.3) / gearChangeIntensityMultiplier (1.0, range 0-1, capped)
  • ProcessPitch seeds the first RPM sample (no false burst from 0→current), uses the passed deltaTime (sample uses fixedDeltaTime).

Optional disableNwhEngineRunningAudio (default true) disables NWH engineRunningComponent so it does not double with VNS continuous banks.

AudioGranulatorSimpleUI (Test Harness)

Standalone tester with sliders, keyboard control, and a configurable rev-limiter fuel-cut stutter. Works with both the New Input System and the Legacy Input Manager.

Common Pitfalls & Tuning Guide

When NOT to use the Deceleration Bank

The deceleration bank is optional. If you leave it empty, VNS automatically sets nonDecelerateAudiosMode = true and reuses the acceleration bank for both directions through the load crossover. Fill it only when you have genuine off-throttle recordings that sound distinctly different from the acceleration clips. Do not fill it with the same clips - that wastes audio sources and blurs the accel/decel distinction unnecessarily.

filterLoad vs smoothedLoad

Raw load (debug ? debugload : _load, packed as filterLoad) drives LPF/HPF/distortion targets and is applied the same fixed tick. smoothedLoad (via loadResponseTime) still drives bank volumes, acc/dec blend, pitch load trim, and burble load gates. Do not expect bank volume to snap with the same immediacy as LPF open/close.

pairHysteresisRpm Tuning

This is the most frequently misconfigured field in the blend system. It creates a dead zone around each clip-pair boundary.

  • Too low (0-50): Clips flicker back and forth audibly near boundaries, especially at steady RPM.
  • Too high (>300): The blend lags behind the actual RPM, making the engine sound disconnected from throttle input.
  • Good starting point: Half the gap between adjacent clip rpmValues (e.g. 500 for 1000-RPM-spaced clips).

loadCrossoverPoint - What Value to Use

The default 0.18 works for most vehicles. It means the accel and decel banks blend 50/50 when engine load is 0.18.

  • Lower (0.05-0.12): Deceleration clips are used more aggressively. The engine switches to decel sounds even under light throttle. Suits vehicles with pronounced engine braking.
  • Higher (0.22-0.35): Acceleration clips dominate more of the load range. Only heavy off-throttle triggers decel sounds. Suits vehicles where decel is barely audible.

clipVolumeResponseTime - Smooth vs Snappy

0.05 is the recommended default. Values below 0.02 make crossfades sound granular and choppy. Values above 0.15 make the engine feel sluggish and unresponsive to throttle changes. This interacts with rpmResponseTime: if the engine feels "slow," check both values - a slow RPM response can mask a fast clip response and vice versa.

rpmdeviation and Edge Clips

rpmdeviation defines the fallback spacing when a clip has only one neighbour (the lowest-RPM and highest-RPM clips in each bank). Set it to roughly the average gap between your clips' rpmValues. If it is too small, the outermost clips blend abruptly (sharp edges). If it is too large, the blend zone extends far beyond where the clip was recorded, producing a washed-out, blurry sound at the extremes.

keepBankClipsPlaying - CPU vs Latency Tradeoff

When enabled (default), every clip loops continuously at zero volume when not active. This eliminates the ~10-50 ms latency of starting an AudioSource from cold, ensuring seamless transitions. The CPU cost is minimal (silent looping costs almost nothing). Disable only if you have 50+ vehicle instances and are seeing genuine audio-thread bottlenecks in the Profiler.

masterVolume vs maxVolumeAcc / maxVolumeDcc

These serve different purposes:

  • masterVolume: Scales everything - both banks, all clips, equally. Use this when the entire vehicle is too loud or too quiet.
  • maxVolumeAcc / maxVolumeDcc: Cap individual banks. If acceleration clips are overpowering but deceleration sounds fine, lower only maxVolumeAcc. Set to 0 for no cap. Values above 1.0 (up to 2.0) can boost a bank that was recorded too quietly.

autoBlip - When to Disable

The autoBlip system detects sharp RPM jumps (typically from downshifts) and momentarily forces the acceleration bank to full blend, creating a realistic throttle-blip sound. Disable it if:

  • You hear unexpected volume spikes during gear changes.
  • Your vehicle uses a CVT or electric drivetrain (no discrete gear changes).
  • You want a smoother, more subdued shift character without the sporty blip.

Cylinder Count and Blend Granularity

Higher cylinder counts produce more firing events per revolution, which shortens the raw pairHoldCycles hold time automatically. A V12 at 6000 RPM fires 600 events/second (a raw ~0.8 ms/cycle); an inline-4 at the same RPM fires only 200 events/second (a raw ~2.5 ms/cycle). Because the selector runs on the fixed-update tick, these raw durations are rounded up to whole Time.fixedDeltaTime ticks before being applied - so at the default pairHoldCycles the effective hold is one tick for every cylinder count, and the cylinder-dependent grading only becomes audible once pairHoldCycles is raised high enough that the raw duration spans multiple ticks (e.g. a low-RPM I4 reaching several ticks while a V12 still rounds to one). Match cylinderCount accurately to the simulated engine, and raise pairHoldCycles until the grain is audible.

Per-Clip Pitch Workflow: Start Broad, Then Narrow

The quick-start recipe (flat pitch curve, all clips near 1.0) neutralizes every tier first. Once the basic blend sounds right:

  1. Broad strokes: Edit the pitchCurve if everything is off (Tier 1).
  2. Bank-level: Use acPitchTrim / dcPitchTrim if one whole bank is off (Tier 2).
  3. Clip-level: Tweak individual loPitch/hiPitch values only as a last resort for that one clip that sounds out of place among its neighbours (Tier 3).

This prevents the common mistake of chasing clip-level pitch values in circles when the real problem is a global offset.

rpmValue Accuracy - The Foundation of the Pitch Model

The v1.9 RPM-ratio pitch formula uses engineRPM / clipRPM as its base. If your rpmValue is wrong by even 10%, the pitch will be off by 10% at that clip. Always set rpmValue to the exact RPM the clip was recorded at before tuning anything else.

Tools & Resources

Creating Seamless Looping Clips

Clean loops are essential for good results: