Overview
Vehicle Noise Synthesizer (VNS) is the audio engine used by ATG Simulator to simulate vehicle sounds based on engine RPM and load. It blends real audio clips recorded at different RPM values using a constant-power crossfade, running on Unity's Burst Job System for maximum performance.
The core algorithm picks the two neighbouring clips that bracket the
current RPM and crossfades them with a constant-power cosine/sine
pan law (cos² + sin² = 1). A hysteresis-buffered pair
selector with cylinder-aware hold timing prevents rapid switching.
On non-WebGL platforms every instance is batched inside a
Burst-compiled job.
Key Features
-
RPM-Ratio Pitch Model: Each clip's base pitch is
engineRPM / clipRPM× global pitch curve, producing physically accurate playback speed that scales correctly at all RPM levels (v1.9). - Burst-Accelerated: Multi-threaded audio calculations via Unity's Job System (non-WebGL).
- Constant-Power Crossfade: Smooth, equal-loudness transitions between RPM clips.
- Active-Pair Visualization: The inspector graph highlights only the two clips currently blending.
-
NWH Vehicle Physics 2 Integration: Direct feed
from
engine.OutputRPMandengine.Loadwith gear-change pitch oscillation. - Three-Tier Pitch Control: Tune pitch globally (pitch curve), per-bank (trim), or per-clip (Lo/Hi multipliers).
-
Throttle Body & DCT Shift (event-driven):
Intake roar, throttle flutter, and DCT shift burble are now
triggered by public methods (
OnThrottleTipIn,OnThrottleTipOut,OnGearShift) called from the integration script — not by internal load-delta thresholds. The old threshold fields are deprecated. - Exhaust Burble & Engine Lugging: Configurable overrun pops and low-RPM strain effects.
What's New in v1.9f NEW
Pitch Model Rewrite — RPM-Ratio Based
-
New formula: Each clip's base pitch is now
engineRPM / clipRPM × globalPitchCurve. This is physically accurate: a clip recorded at 2000 RPM plays at 2× speed when the engine reaches 4000 RPM, before any per-clip multipliers. -
Per-clip fields renamed:
minPitch/maxPitch(absolute clamps, default 0.5–2.5) are nowloPitch/hiPitch— multipliers on top of the RPM-ratio pitch, defaulting to 1.0 (neutral, no effect). -
rpmPitchTrackingremoved — the new ratio model makes per-clip tracking strength redundant. -
targetedShiftPitchremoved — global pitch shaping is now done exclusively through thepitchCurve(Tier 1). -
idlePitchremoved — the ratio model naturally produces correct pitch at all RPM including idle. -
pitchCurvedefault is now a flat constant 1.0 (was 0.97→1.03).
New Audio Features
-
Throttle Body Effects (event-driven): Intake roar
and throttle flutter are now triggered by public methods (
OnThrottleTipIn/OnThrottleTipOut) called from the integration script when the player's throttle input jumps 0→1 or 1→0. The olddeltaLoadthreshold fields (intakeRoarLoadDeltaThreshold,throttleFlutterLoadDeltaThreshold) are deprecated and no longer read. -
DCT Shift Burble (event-driven): The DCT exhaust
overlay is now fired exclusively by
OnGearShift()on gear change, instead of the olddeltaLoad-based trigger. ThedctShiftBurbleFiredThisDecreaseflag is removed. A 30ms grace period prevents transmission-engagement noise from cutting off the burble; load increase still stops it immediately after the grace window. - Exhaust Redline Effect: Repeating one-shot crackle/pressure-wave clips while RPM stays within a configurable redline window. Delay and pitch are randomised.
-
Burble window: Single
burbleLoadThresholdreplaced byburbleLoadLowThreshold+burbleLoadHighThreshold— burble now fires within a configurable load window instead of only below a threshold.
Editor UX & Workflow
- RPM field is now a plain integer text box (no more Range slider).
- Pitch Lo/Hi sliders show numeric readouts with "0" and "4" endpoint labels on the blue range bar.
- Active-pair highlighting: The volume envelope graph highlights only the two active neighbour clips; inactive clips dim to 13%.
-
No more auto-sort: Editor clip order is
preserved; sorting happens locally at runtime inside
BuildRpmTablesandBuildBankLayers. -
Debug RPM markers follow
debugrpmin both edit and play modes.
Carried Forward from v1.8f2
- Combustion Timing: Cylinder-aware pair-hold turns the blend into a granular, looped system.
- Constant-power crossfade (cos² + sin² = 1), hysteresis fixes, rev-limiter cutoff, engine lugging system.
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.
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.
pitchCurve (AnimationCurve)Section: Global Curves
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.
acPitchTrim / dcPitchTrimSection: Tuning
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.
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.
The final pitch formula for each clip at runtime is:
pitch = (engineRPM / clipRPM) × globalPitchCurve ×
Lerp(loPitch, hiPitch, progress) + bankPitchTrim + pitchOffset
Lo and Hi interpolate smoothly as RPM climbs through that clip's window. The blue bar visualizes where that window sits on the full 0.01 to 4.0 scale, so you can see at a glance how wide and how high each clip reaches.
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.
-
Set the
pitchCurve(Global Curves) to a flat constant 1.0 (the default). -
Set every clip's Lo and
Hi values to 1.0 (neutral).
With correct
rpmValueand 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. -
Set
acPitchTrimanddcPitchTrim(Tuning) to 0. -
Before anything else, assign the correct
rpmValueto every clip in the banks. This is the single most important data point — the entire RPM-ratio model depends on it. -
Enable
debug, then sweepdebugrpmacross the range and listen. Adjust by ear, starting from the broadest tier that helps.
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.MathematicsandUnity.Burstpackages (install via Package Manager). - NWH Vehicle Physics 2 (included in the ATG Simulator project).
Adding VNS to a Vehicle
-
Add the
VehicleNoiseSynthesizercomponent to your vehicle's audio root GameObject (menu: "ATG Audio / Vehicle Noise Synthesizer"). -
Assign an
AudioSourcetoaudioSourceTemplate. The pooling system copies its 3D settings for every generated source. -
Populate
acceleratingSoundswith your clips. For each, set theAudioClipand therpmValueit was recorded at. TherpmValuefield is a plain integer text box in v1.9f — type exact values. -
Set each clip's
loPitchandhiPitchmultipliers (default 1.0 = neutral). Watch the active-pair volume graph confirm your blends. -
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.
Full Parameter Reference
Every parameter on the component, grouped by its inspector section. Pitch-related fields are tagged with their tier. All defaults and ranges match the v1.9 source code exactly.
Debug Controls
-
debug(bool, default false):Manually override RPM/load for testing so the NWH Vehicle Controller does not dictate them.
debugrpmanddebugloadthen drive the audio. Markers followdebugrpmin both edit and play modes. -
debugrpm(float, 100–9000, default 800):Test RPM value used while debug is on.
-
debugload(float, 0–1, default 1):Test engine load value used while debug is on.
-
enableDiagnosticLogger(bool, default false):Prints per-clip volume/pitch state to the console once per second.
-
enableBurbleDiagnostics(bool, default false):Logs burble gate decisions to 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, measured in combustion-event cycles. The combustion-derived duration is rounded up to whole physics ticks (
Time.fixedDeltaTime) before it is applied, because the pair selector is evaluated inside aWaitForFixedUpdateloop and a sub-tick hold would expire before it could ever block a switch. A value of0disables the hold (thepairHysteresisRpmmargin still limits switching). Raise it for longer, more audible stability.
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
You can use one clip for both directions, or a series of clips per
bank. 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–10, default 1) Pitch Tier 3:Multiplier applied to the RPM-ratio pitch at the lowest RPM of this clip's window. Default 1.0 = neutral (no scaling — the RPM-ratio model runs automatically). This is an artistic fine-tuning control; with correct
rpmValueand well-recorded clips, leave at 1.0. FormerlyminPitchin v1.8. -
hiPitch(float, 0.01–10, default 1) Pitch Tier 3:Multiplier applied to the RPM-ratio pitch at the highest RPM of this clip's window. Default 1.0 = neutral (no scaling — the RPM-ratio model runs automatically). This is an artistic fine-tuning control; with correct
rpmValueand well-recorded clips, leave at 1.0. FormerlymaxPitchin v1.8. -
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
useSharedMixerReverbis 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.
-
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.
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 clips. Final volume is scaled linearly by normalised RPM.
-
throttleFlutterVolume(float, 0–1, default 0.5):Master volume for throttle flutter clips. Final volume is scaled linearly by normalised RPM.
-
throttleBodyPitchVariation(float, 0–0.3, default 0.05):Random ±pitch variation applied to each throttle body one-shot.
-
intakeRoarLoadDeltaThreshold(float, 0.005–0.5, default 0.05) DEPRECATED:No longer used. Intake roar is now triggered via
OnThrottleTipIn()called from the integration script. This field is kept for serialization compatibility but is not read by any logic. -
throttleFlutterLoadDeltaThreshold(float, 0.005–0.5, default 0.05) DEPRECATED:No longer used. Throttle flutter is now triggered via
OnThrottleTipOut()called from the integration script. This field is kept for serialization compatibility but is not read by any logic. -
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.
Burble & Lugging
-
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 and crackle. Burble fires when load is within the window [
burbleLoadLowThreshold,burbleLoadHighThreshold) — the low threshold prevents burble during full coasting, the high threshold suppresses it under power. -
enableEngineLugging(bool, default true) +luggingSounds,luggingVolume(0–1, default 0.8),luggingMinRPMThreshold(default 800),luggingMaxRPMThreshold(default 2000),luggingMinLoadThreshold(0–1, default 0.7),luggingFadeInSpeed(0.1–20, default 5),luggingFadeOutSpeed(0.1–20, default 3),luggingBasePitch(0.5–1.5, default 0.9),luggingRandomPitchVariation(0–0.2, default 0.05):Low-RPM, high-load strain sound.
-
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):DCT Shift Burble (event-driven). A looping exhaust overlay fired on gear change via
OnGearShift(). Plays for up todctShiftBurbleMaxDurationbut cuts off immediately if engine load increases (after a 30ms grace period to ignore transmission-engagement noise). Volume is scaled by RPM viadctShiftBurbleRpmVolumeInfluence.
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:
enableThrottleBodymust be true;_isOnmust be true (engine running); cooldown must be elapsed. -
Volume:
intakeRoarVolume × throttleValue × engineLoad— if the engine is off (load=0), volume is zero. - 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:
enableThrottleBodymust be true;_isOnmust 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:
enableDctShiftBurblemust be true;dctShiftBurbleSoundmust 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/onStopevents to callTurnOn()/TurnOff(). -
Each
FixedUpdatepassesengine.OutputRPMtorpmandengine.Loadtoload. -
Throttle tracking: Tracks
vp.input.Throttleacross ticks. When throttle jumps 0→1 (below 0.2 to above 0.8), callsOnThrottleTipIn(throttle, rpm, engineLoad). When it drops 1→0, callsOnThrottleTipOut(rpm, engineLoad). The 0.2/0.8 hysteresis bands prevent noise at transition boundaries. -
Detects gear changes, drives the
EnginePitchOscillator (writing to
shiftPitchOsc), and callsOnGearShift()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
-
oscillationSpeed/oscillationDepth:Base speed and maximum amount of the pitch wobble.
-
rpmIncreaseThreshold/rpmDecreaseThreshold/revLimiterThreshold:RPM deltas that trigger the effect.
-
dampingFactor/loadInfluence/effectDelay:Fade-out rate, load sensitivity, and onset delay.
-
harmonicFrequency/harmonicAmplitude/gearChangeIntensityMultiplier:Secondary oscillation and gear-shift boost.
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.
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 onlymaxVolumeAcc. 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:
-
Broad strokes: Edit the
pitchCurveif everything is off (Tier 1). -
Bank-level: Use
acPitchTrim/dcPitchTrimif one whole bank is off (Tier 2). -
Clip-level: Tweak individual
loPitch/hiPitchvalues 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:
- Audacity (free): Create Looping Sound Effects for Free
- Audacity (advanced): Seamlessly Loop Any Audio
- Online looper: Drumbot Online Audio Looper
- Pitch correction (paid): Pitch Correcting Engine Noises