From 450f1b6ebf760d3420696ef9544557d00ff9a87f Mon Sep 17 00:00:00 2001 From: Dan Date: Fri, 25 Oct 2024 22:45:16 +0200 Subject: [PATCH 1/3] init --- Depiction.jpg.meta | 2 ++ LICENSE.meta | 2 ++ README.md.meta | 2 ++ The 'Assets' folder of your Unity Prjct.meta | 8 ++++++++ 4 files changed, 14 insertions(+) create mode 100644 Depiction.jpg.meta create mode 100644 LICENSE.meta create mode 100644 README.md.meta create mode 100644 The 'Assets' folder of your Unity Prjct.meta diff --git a/Depiction.jpg.meta b/Depiction.jpg.meta new file mode 100644 index 0000000..037d197 --- /dev/null +++ b/Depiction.jpg.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 85168ba1a6bbeaf41af73fc43d64aebb \ No newline at end of file diff --git a/LICENSE.meta b/LICENSE.meta new file mode 100644 index 0000000..5e1b4f9 --- /dev/null +++ b/LICENSE.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: a0b2ec91e6ea0ec459ee89db7bbd3b3a \ No newline at end of file diff --git a/README.md.meta b/README.md.meta new file mode 100644 index 0000000..73dd6e9 --- /dev/null +++ b/README.md.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 9cc450a78cfa0c746b972c67466d253e \ No newline at end of file diff --git a/The 'Assets' folder of your Unity Prjct.meta b/The 'Assets' folder of your Unity Prjct.meta new file mode 100644 index 0000000..1c03096 --- /dev/null +++ b/The 'Assets' folder of your Unity Prjct.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 2be47d5f71beb3845a544127750bf5e9 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: From 43e18596b96665abacfb6e77215d399055d15f36 Mon Sep 17 00:00:00 2001 From: Dan Date: Sat, 26 Oct 2024 00:22:30 +0200 Subject: [PATCH 2/3] version 1.2f added animation curves, better ui, added sample scene, bug fixes. --- Depiction.jpg.meta | 127 ++- LICENSE.meta | 7 +- README.md.meta | 7 +- .../NWH_BoatSampleDemo.unity | Bin 8006388 -> 8029192 bytes .../NWH_VehicleSampleDemo.unity | 783 ++++++++++++++++-- .../Scripts/Core/VehicleNoiseSynthesizer.cs | 179 ++-- .../Scripts/Inputs/AudioGranulatorSimpleUI.cs | 97 +++ .../Inputs/AudioGranulatorSimpleUI.cs.meta | 11 + .../AudioGranulatorNWHDynamicWaterPhysics2.cs | 2 + .../AudioGranulatorNWHVehiclePhysics2.cs | 2 + .../VNS Example UI Simple Scene.unity | 221 +++++ .../VNS Example UI Simple Scene.unity.meta | 7 + 12 files changed, 1336 insertions(+), 107 deletions(-) create mode 100644 The 'Assets' folder of your Unity Prjct/Vehicle Noise Synthesizer/Scripts/Inputs/AudioGranulatorSimpleUI.cs create mode 100644 The 'Assets' folder of your Unity Prjct/Vehicle Noise Synthesizer/Scripts/Inputs/AudioGranulatorSimpleUI.cs.meta create mode 100644 The 'Assets' folder of your Unity Prjct/Vehicle Noise Synthesizer/VNS Example UI Simple Scene.unity create mode 100644 The 'Assets' folder of your Unity Prjct/Vehicle Noise Synthesizer/VNS Example UI Simple Scene.unity.meta diff --git a/Depiction.jpg.meta b/Depiction.jpg.meta index 037d197..fc59463 100644 --- a/Depiction.jpg.meta +++ b/Depiction.jpg.meta @@ -1,2 +1,127 @@ fileFormatVersion: 2 -guid: 85168ba1a6bbeaf41af73fc43d64aebb \ No newline at end of file +guid: 85168ba1a6bbeaf41af73fc43d64aebb +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 13 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 1 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 1 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 8 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: 5e97eb03825dee720800000000000000 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/LICENSE.meta b/LICENSE.meta index 5e1b4f9..be5e762 100644 --- a/LICENSE.meta +++ b/LICENSE.meta @@ -1,2 +1,7 @@ fileFormatVersion: 2 -guid: a0b2ec91e6ea0ec459ee89db7bbd3b3a \ No newline at end of file +guid: a0b2ec91e6ea0ec459ee89db7bbd3b3a +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/README.md.meta b/README.md.meta index 73dd6e9..93c653f 100644 --- a/README.md.meta +++ b/README.md.meta @@ -1,2 +1,7 @@ fileFormatVersion: 2 -guid: 9cc450a78cfa0c746b972c67466d253e \ No newline at end of file +guid: 9cc450a78cfa0c746b972c67466d253e +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/The 'Assets' folder of your Unity Prjct/Vehicle Noise Synthesizer/DemoSceneNWHSample/NWH_BoatSampleDemo.unity b/The 'Assets' folder of your Unity Prjct/Vehicle Noise Synthesizer/DemoSceneNWHSample/NWH_BoatSampleDemo.unity index 2a1f32135b864000f2c38ffea892b8cf3fb4cb16..cf9c0043b3738e1284f1fe8041b5d46c87538824 100644 GIT binary patch delta 22168 zcmbt+dt6l2`u<*f02#TBB662ON5wmc6)GZ%A|NU%8YT)TqhQ?RCW9ncR#c|wHW!)~ ztUOtnQB*_ag>$r`lNpvNr%WlW%wvY8NoM+c-*p)rI)4B8?T_#5Squ%Y;QJ(YGXiz;z6h$xW9#E93j}$Ge=6)^dRfmRB-F_!6X`h4s6VQQw zN<_oi?q8FJ(Mnz<-TyAima zmi=lmI{Jg}an|4&WU)?j?;A&_6sktYegHNi_@s^wEhPaBeFmgD^BY~4EG@Iiq+eZYo2AAe}?(GaGftvM++M1rPb@4gwFVp=xzQ; zsdJX;RNCq6WI7+%bgnX;vvxXnn2vwA^mCi(j1Rv%ue5M~{Q|%pKpxOu4F4yc*jw$T ztr<1d*lpBW{qC~BkA4h@ee1_Ze;A~%ZhxU((OpQ`?*3AJY@lnyucM|o4Ja*f8C#v& z>X4PinK?mPhviVNy%L_cNrn;q#_`LrcS9dO- z^Jd03Ghc#?AJkc|l#(SnZ9&?$FcrFpCv=MCK)^`4V}!d>g&+LFPV*JiX$VoOkPp_b zY!4!RwV8E6f!IZH+{jA@^{RlxGVoy3g2KE!99f5Z95AeLe=TgMryF*`rv);=hSUgT zpbe=NNQkzf&RY*w%*P;1IlK-jI=+JRcHud^k1S2EATrCtLVc)q1&luvsbMVjjYtj0 zRNsptH3IH;S4IZrrb7R!AU+=UVF+Vk7>QvB4)0=V7Y5))*{UQ1ai0y5fw

$Ur=R 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 L7Dk3ThA|fIxDk7i=C?X;nZU}2yk{YgFb?}AQ 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 acceleratingSounds = new List(); + [Tooltip("[Optional] Audio clips for engine deceleration with their respective RPM values")] + public List deceleratingSounds = new List(); // Mimimum and Maximum values of volumes [Tooltip("If there is no decelrating sound clips, the accelerating sound clip with the lowest RPM value is chosen and this will be its default volume when it is idle.")] @@ -49,12 +99,6 @@ public class VehicleNoiseSynthesizer : MonoBehaviour public float maxVolumeAcc = 0.4f; [Range(0.00f, 1.00f)] public float maxVolumeDcc = 0.1f; - [Range(0.00f, 1.00f)] - public float pitchRange = 0.2f; - [Range(0.1f, 2.00f)] - public float minPitch = 0.6f; - [Range(0.001f, 100.00f)] - public float pitchConstant = 0.4f; [Space(7f)] [Header("Advanced Granulator Properties")] @@ -86,6 +130,7 @@ public float load { get; internal set; // sets the load value based on one of the inputs like the provided "AudioGranulatorNWHVehiclePhysics2" class } + [Space(47f)] [Header("[Read-Only] Debug Values")] [Space(7f)] @@ -123,6 +168,7 @@ public float load private List _accelerateAudios; private List _decelerateAudios; float vol; + public enum MixerType { Intake, @@ -131,7 +177,6 @@ public enum MixerType Transmission, Differential } - internal void Activate(float maxRpm, float idleRpm) { //max rpm of the engine @@ -142,17 +187,17 @@ internal void Activate(float maxRpm, float idleRpm) // one-time process to prepare and load audio clips _nonDecelerateAudiosMode = true; int counter = 0; - _AcNormal_rTable = new float[acceleratingSounds.Length]; - foreach (AudioClip item in acceleratingSounds) + _AcNormal_rTable = new float[acceleratingSounds.Count]; + foreach (EngineAudioClipData item in acceleratingSounds) { - _AcNormal_rTable[counter] = Get_r(item.name); + _AcNormal_rTable[counter] = item.rpmValue; counter++; } counter = 0; - _DcNormal_rTable = new float[deceleratingSounds.Length]; - foreach (AudioClip item in deceleratingSounds) + _DcNormal_rTable = new float[deceleratingSounds.Count]; + foreach (EngineAudioClipData item in deceleratingSounds) { - _DcNormal_rTable[counter] = Get_r(item.name); + _DcNormal_rTable[counter] = item.rpmValue; counter++; } // if no decelerating audio clips are provided - like for vehicle engine and vehicle engine intake sounds - then this changes the script behavior accordingly @@ -186,13 +231,12 @@ internal void Activate(float maxRpm, float idleRpm) Transform T = this.gameObject.transform; - if (acceleratingSounds.Length <= 0) + if (acceleratingSounds.Count <= 0) { throw new System.Exception("No Audios provided!"); } AudioSource carSound; - AudioLowPassFilter aLpf; List ks = new List() { new Keyframe(0,1), @@ -214,7 +258,7 @@ internal void Activate(float maxRpm, float idleRpm) carSound = gameObject.AddComponent(); carSound.playOnAwake = false; carSound.reverbZoneMix = audioSourceTemplate.reverbZoneMix; - carSound.spatialBlend = 1; + carSound.spatialBlend = audioSourceTemplate.spatialBlend; carSound.dopplerLevel = audioSourceTemplate.dopplerLevel; carSound.spread = audioSourceTemplate.spread; carSound.rolloffMode = audioSourceTemplate.rolloffMode; @@ -225,15 +269,13 @@ internal void Activate(float maxRpm, float idleRpm) carSound.transform.parent = T; carSound.volume = 0; carSound.loop = true; - carSound.clip = sound; + carSound.clip = sound.audioClip; if (mixer) carSound.outputAudioMixerGroup = mixer; _accelerateAudios.Add(carSound); - // - aLpf = gameObject.AddComponent(); - aLpf.customCutoffCurve = aC; + AddAudioEffects(carSound); } foreach (var sound in deceleratingSounds) { @@ -242,7 +284,7 @@ internal void Activate(float maxRpm, float idleRpm) carSound = gameObject.AddComponent(); carSound.playOnAwake = false; carSound.reverbZoneMix = audioSourceTemplate.reverbZoneMix; - carSound.spatialBlend = 1; + carSound.spatialBlend = audioSourceTemplate.spatialBlend; carSound.dopplerLevel = audioSourceTemplate.dopplerLevel; carSound.spread = audioSourceTemplate.spread; carSound.rolloffMode = audioSourceTemplate.rolloffMode; @@ -253,18 +295,27 @@ internal void Activate(float maxRpm, float idleRpm) carSound.transform.parent = T; carSound.volume = 0; carSound.loop = true; - carSound.clip = sound; + carSound.clip = sound.audioClip; if (mixer) carSound.outputAudioMixerGroup = mixer; _decelerateAudios.Add(carSound); - // - aLpf = gameObject.AddComponent(); - aLpf.customCutoffCurve = aC; + AddAudioEffects(carSound); } } + private void AddAudioEffects(AudioSource source) + { + // Add Low Pass Filter + AudioLowPassFilter lowPass = source.gameObject.AddComponent(); + lowPass.cutoffFrequency = 22000f; // Start with no filtering + + // Add Distortion + AudioDistortionFilter distortion = source.gameObject.AddComponent(); + distortion.distortionLevel = 0f; + } + internal void TurnOn() { _isOn = true; @@ -275,27 +326,14 @@ internal void TurnOff() _isOn = false; } - // Function to assign each audio clip its correct RPM value based on its file name, always the last "_" charachter would make the component save rpm values. E.g: Some_Name_123_9000.wav would register 9000 as the rpm value assigned to the audio clip - private float Get_r(string name) - { - string num = string.Empty; - foreach (char c in name) - { - if (c == '_') - { - num = ""; - continue; - } - num += c; - } - return float.Parse(num.Replace("_", "")); - } void CalcVolPitchAcDc(float load, bool acDc) { if (_accelerateAudios == null) // If audio sources are not ready yet, ignore doing this function. return; - _finalPitch = Mathf.Lerp(_finalPitch, (_rpm > _idleRpm + rpm_deviation ? (pitchConstant * (Mathf.Pow(((_rpm + 1) / (_maxRpm + 1)), 2) + 0.5f) + (load * pitchRange)) + minPitch : 1f), Time.deltaTime * transitionTime); + float normalizedRPM = Mathf.InverseLerp(_idleRpm, _maxRpm, _rpm); + float pitchMultiplier = pitchCurve.Evaluate(normalizedRPM); + _finalPitch = Mathf.Lerp(_finalPitch, (_rpm > _idleRpm + rpm_deviation ? pitchMultiplier : 1f), Time.deltaTime * transitionTime); if (l_r + 75 < _rpm || _nonDecelerateAudiosMode || load > 0f) { @@ -307,9 +345,9 @@ void CalcVolPitchAcDc(float load, bool acDc) _finalAccVol = Mathf.Lerp(_finalAccVol, 0.0f, Time.deltaTime * transitionTime); _finalDecVol = Mathf.Lerp(_finalDecVol, 1.0f, Time.deltaTime * transitionTime); } + if (_accelerateAudios.Count == 1) // Calculation for when only one audio clip is used { - if (!_isOn || _rpm < 100) { _accelerateAudios[0].pitch = 1; @@ -320,12 +358,14 @@ void CalcVolPitchAcDc(float load, bool acDc) if (!_accelerateAudios[0].isPlaying) _accelerateAudios[0].Play(); + float volumeMultiplier = volumeCurve.Evaluate(normalizedRPM); if (maxVolumeAcc > 0) - _accelerateAudios[0].volume = Mathf.Clamp(MathF.Pow(((_rpm + 100) / _maxRpm), 2), idleAccVolume, maxVolumeAcc) * masterVolume; + _accelerateAudios[0].volume = volumeMultiplier * Mathf.Clamp(volumeMultiplier + idleAccVolume, idleAccVolume, maxVolumeAcc) * masterVolume; else - _accelerateAudios[0].volume = 1 * masterVolume; + _accelerateAudios[0].volume = volumeMultiplier * masterVolume; _accelerateAudios[0].pitch = Mathf.Lerp(_accelerateAudios[0].pitch, _finalPitch + shiftPitch + acPitchTrim, Time.deltaTime * (acPitchTransitionTime)) + rndmPitch; + ApplyAudioEffects(_accelerateAudios[0], normalizedRPM, load); } } else // Calculation for when either both audio clip types are used or more than one accelerating sound clip is used @@ -364,13 +404,15 @@ void CalcVolPitchAcDc(float load, bool acDc) if (_rpm > 0) { _accelerateAudios[i].pitch = Mathf.Lerp(_accelerateAudios[i].pitch, _rpm <= _idleRpm + rpm_deviation ? idlePitch : _finalPitch + shiftPitch + acPitchTrim, Time.deltaTime * (acPitchTransitionTime)) + rndmPitch; + + float volumeMultiplier = volumeCurve.Evaluate(normalizedRPM); if (maxVolumeAcc > 0) { - _accelerateAudios[i].volume = vol * Mathf.Clamp(((_rpm + 100) / _maxRpm) + idleAccVolume, _decelerateAudios.Count == 0 ? (_rpm <= _idleRpm ? idleAccVolume : 0) : 0f, maxVolumeAcc) * masterVolume; + _accelerateAudios[i].volume = vol * Mathf.Clamp(volumeMultiplier + idleAccVolume, _decelerateAudios.Count == 0 ? (_rpm <= _idleRpm ? idleAccVolume : 0f) : 0f, maxVolumeAcc) * masterVolume; } else { - _accelerateAudios[i].volume = vol * masterVolume; + _accelerateAudios[i].volume = vol * volumeMultiplier * masterVolume; } if (!_accelerateAudios[i].isPlaying) _accelerateAudios[i].Play(); @@ -378,6 +420,7 @@ void CalcVolPitchAcDc(float load, bool acDc) else _accelerateAudios[i].volume = 0; } + ApplyAudioEffects(_accelerateAudios[i], normalizedRPM, load); } } } @@ -417,24 +460,29 @@ void CalcVolPitchAcDc(float load, bool acDc) if (_rpm > 0) { _decelerateAudios[i].pitch = Mathf.Lerp(_decelerateAudios[i].pitch, _rpm <= _idleRpm + rpm_deviation ? idlePitch : _finalPitch + shiftPitch + dcPitchTrim, Time.deltaTime * (dcPitchTransitionTime)) + rndmPitch; + + normalizedRPM = Mathf.InverseLerp(_idleRpm, _maxRpm, _rpm); + float volumeMultiplier = volumeCurve.Evaluate(normalizedRPM); + if (maxVolumeDcc > 0) { - _decelerateAudios[i].volume = vol * Mathf.Clamp(((_rpm + 100) / (_maxRpm / 2)) + idleAccVolume, 0, maxVolumeDcc) * masterVolume; + _decelerateAudios[i].volume = vol * Mathf.Clamp(volumeMultiplier + idleAccVolume, 0, maxVolumeDcc) * masterVolume; } else { - _decelerateAudios[i].volume = vol * masterVolume; + _decelerateAudios[i].volume = vol * volumeMultiplier * masterVolume; } + if (!_decelerateAudios[i].isPlaying) _decelerateAudios[i].Play(); } else _decelerateAudios[i].volume = 0; } + ApplyAudioEffects(_accelerateAudios[i], normalizedRPM, load); } } } - // l_r = _rpm; } @@ -465,6 +513,29 @@ IEnumerator CalculateAsync() } } + private void ApplyAudioEffects(AudioSource source, float normalizedRPM, float load) + { + // Get the audio effect components + AudioLowPassFilter lowPass = source.GetComponent(); + AudioDistortionFilter distortion = source.GetComponent(); + + if (lowPass == null || distortion == null) + return; + + // Calculate combined load/RPM factor for effects + float loadFactor = Mathf.Lerp(1f - load, 1f, 1f - mufflingIntensity); + float rpmFactor = normalizedRPM; + float combinedFactor = (loadFactor + rpmFactor) * 0.5f; + + // Apply low pass filter + float cutoffFrequency = lowPassCurve.Evaluate(1f - loadFactor) * lowPassIntensity; + lowPass.cutoffFrequency = cutoffFrequency; + + // Apply distortion + float distortionAmount = distortionCurve.Evaluate(combinedFactor) * distortionIntensity; + distortion.distortionLevel = distortionAmount; + } + private void OnEnable() { StartCoroutine(CalculateAsync()); @@ -476,4 +547,4 @@ private void OnDisable() StopCoroutine(CalculateAsync()); } } -} +} \ No newline at end of file diff --git a/The 'Assets' folder of your Unity Prjct/Vehicle Noise Synthesizer/Scripts/Inputs/AudioGranulatorSimpleUI.cs b/The 'Assets' folder of your Unity Prjct/Vehicle Noise Synthesizer/Scripts/Inputs/AudioGranulatorSimpleUI.cs new file mode 100644 index 0000000..661df61 --- /dev/null +++ b/The 'Assets' folder of your Unity Prjct/Vehicle Noise Synthesizer/Scripts/Inputs/AudioGranulatorSimpleUI.cs @@ -0,0 +1,97 @@ +using AroundTheGroundSimulator; +using UnityEngine; +using UnityEngine.UI; + +[RequireComponent(typeof(VehicleNoiseSynthesizer))] +public class AudioGranulatorSimpleUI : MonoBehaviour +{ + private VehicleNoiseSynthesizer synthesizer; + + [Header("UI Controls")] + public Slider rpmSlider; // Reference to RPM UI slider + public Slider loadSlider; // Reference to Load UI slider + public Text rpmText; // Optional: Text to display current RPM + public Text loadText; // Optional: Text to display current Load + + [Header("RPM Settings")] + public float minRPM = 800f; // Minimum RPM value + public float maxRPM = 8000f; // Maximum RPM value + + [Header("Load Settings")] + public float minLoad = 0f; // Minimum Load value + public float maxLoad = 1f; // Maximum Load value + + private void Start() + { + // Get reference to the VehicleNoiseSynthesizer + synthesizer = GetComponent(); + synthesizer._debug = true; + + // Initialize sliders + InitializeSliders(); + + // Add listeners to sliders + rpmSlider.onValueChanged.AddListener(OnRPMChanged); + loadSlider.onValueChanged.AddListener(OnLoadChanged); + } + + private void InitializeSliders() + { + // Setup RPM slider + if (rpmSlider != null) + { + rpmSlider.minValue = minRPM; + rpmSlider.maxValue = maxRPM; + rpmSlider.value = minRPM; + } + + // Setup Load slider + if (loadSlider != null) + { + loadSlider.minValue = minLoad; + loadSlider.maxValue = maxLoad; + loadSlider.value = minLoad; + } + + synthesizer.Activate(maxRPM, minRPM); + synthesizer.TurnOn(); + // Initial update of values + UpdateSynthesizerValues(); + } + + private void OnRPMChanged(float value) + { + UpdateSynthesizerValues(); + UpdateUIText(); + } + + private void OnLoadChanged(float value) + { + UpdateSynthesizerValues(); + UpdateUIText(); + } + + private void UpdateSynthesizerValues() + { + if (synthesizer != null) + { + synthesizer.debug_rpm = rpmSlider.value; + synthesizer.debug_load = loadSlider.value; + } + } + + private void UpdateUIText() + { + // Update RPM text if available + if (rpmText != null) + { + rpmText.text = $"RPM: {rpmSlider.value:F0}"; + } + + // Update Load text if available + if (loadText != null) + { + loadText.text = $"Load: {loadSlider.value:F2}"; + } + } +} \ No newline at end of file diff --git a/The 'Assets' folder of your Unity Prjct/Vehicle Noise Synthesizer/Scripts/Inputs/AudioGranulatorSimpleUI.cs.meta b/The 'Assets' folder of your Unity Prjct/Vehicle Noise Synthesizer/Scripts/Inputs/AudioGranulatorSimpleUI.cs.meta new file mode 100644 index 0000000..05a7506 --- /dev/null +++ b/The 'Assets' folder of your Unity Prjct/Vehicle Noise Synthesizer/Scripts/Inputs/AudioGranulatorSimpleUI.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b82487133bf468743b57563216f4dfdc +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/The 'Assets' folder of your Unity Prjct/Vehicle Noise Synthesizer/Scripts/Inputs/NWH-Physics_IntegrationSample/AudioGranulatorNWHDynamicWaterPhysics2.cs b/The 'Assets' folder of your Unity Prjct/Vehicle Noise Synthesizer/Scripts/Inputs/NWH-Physics_IntegrationSample/AudioGranulatorNWHDynamicWaterPhysics2.cs index 72ced44..d18e11f 100644 --- a/The 'Assets' folder of your Unity Prjct/Vehicle Noise Synthesizer/Scripts/Inputs/NWH-Physics_IntegrationSample/AudioGranulatorNWHDynamicWaterPhysics2.cs +++ b/The 'Assets' folder of your Unity Prjct/Vehicle Noise Synthesizer/Scripts/Inputs/NWH-Physics_IntegrationSample/AudioGranulatorNWHDynamicWaterPhysics2.cs @@ -1,3 +1,4 @@ +/**************************************************************************************** Uncomment if NWH Installed using NWH.DWP2; using NWH.DWP2.ShipController; using System; @@ -43,3 +44,4 @@ private void FixedUpdate() } } } +*******************************************************************************************************************/ \ No newline at end of file diff --git a/The 'Assets' folder of your Unity Prjct/Vehicle Noise Synthesizer/Scripts/Inputs/NWH-Physics_IntegrationSample/AudioGranulatorNWHVehiclePhysics2.cs b/The 'Assets' folder of your Unity Prjct/Vehicle Noise Synthesizer/Scripts/Inputs/NWH-Physics_IntegrationSample/AudioGranulatorNWHVehiclePhysics2.cs index 877c651..ec58408 100644 --- a/The 'Assets' folder of your Unity Prjct/Vehicle Noise Synthesizer/Scripts/Inputs/NWH-Physics_IntegrationSample/AudioGranulatorNWHVehiclePhysics2.cs +++ b/The 'Assets' folder of your Unity Prjct/Vehicle Noise Synthesizer/Scripts/Inputs/NWH-Physics_IntegrationSample/AudioGranulatorNWHVehiclePhysics2.cs @@ -1,3 +1,4 @@ +/**************************************************************************************** Uncomment if NWH Installed using NWH.VehiclePhysics2; using System.Collections; using System.Collections.Generic; @@ -36,3 +37,4 @@ private void FixedUpdate() } } } +*******************************************************************************************************************/ \ No newline at end of file diff --git a/The 'Assets' folder of your Unity Prjct/Vehicle Noise Synthesizer/VNS Example UI Simple Scene.unity b/The 'Assets' folder of your Unity Prjct/Vehicle Noise Synthesizer/VNS Example UI Simple Scene.unity new file mode 100644 index 0000000..3e6bb99 --- /dev/null +++ b/The 'Assets' folder of your Unity Prjct/Vehicle Noise Synthesizer/VNS Example UI Simple Scene.unity @@ -0,0 +1,221 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!29 &1 +OcclusionCullingSettings: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_OcclusionBakeSettings: + smallestOccluder: 5 + smallestHole: 0.25 + backfaceThreshold: 100 + m_SceneGUID: 00000000000000000000000000000000 + m_OcclusionCullingData: {fileID: 0} +--- !u!104 &2 +RenderSettings: + m_ObjectHideFlags: 0 + serializedVersion: 9 + m_Fog: 0 + m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1} + m_FogMode: 3 + m_FogDensity: 0.01 + m_LinearFogStart: 0 + m_LinearFogEnd: 300 + m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1} + m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1} + m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1} + m_AmbientIntensity: 1 + m_AmbientMode: 3 + m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1} + m_SkyboxMaterial: {fileID: 0} + m_HaloStrength: 0.5 + m_FlareStrength: 1 + m_FlareFadeSpeed: 3 + m_HaloTexture: {fileID: 0} + m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0} + m_DefaultReflectionMode: 0 + m_DefaultReflectionResolution: 128 + m_ReflectionBounces: 1 + m_ReflectionIntensity: 1 + m_CustomReflection: {fileID: 0} + m_Sun: {fileID: 0} + m_UseRadianceAmbientProbe: 0 +--- !u!157 &3 +LightmapSettings: + m_ObjectHideFlags: 0 + serializedVersion: 12 + m_GIWorkflowMode: 1 + m_GISettings: + serializedVersion: 2 + m_BounceScale: 1 + m_IndirectOutputScale: 1 + m_AlbedoBoost: 1 + m_EnvironmentLightingMode: 0 + m_EnableBakedLightmaps: 0 + m_EnableRealtimeLightmaps: 0 + m_LightmapEditorSettings: + serializedVersion: 12 + m_Resolution: 2 + m_BakeResolution: 40 + m_AtlasSize: 1024 + m_AO: 0 + m_AOMaxDistance: 1 + m_CompAOExponent: 1 + m_CompAOExponentDirect: 0 + m_ExtractAmbientOcclusion: 0 + m_Padding: 2 + m_LightmapParameters: {fileID: 0} + m_LightmapsBakeMode: 1 + m_TextureCompression: 1 + m_FinalGather: 0 + m_FinalGatherFiltering: 1 + m_FinalGatherRayCount: 256 + m_ReflectionCompression: 2 + m_MixedBakeMode: 2 + m_BakeBackend: 1 + m_PVRSampling: 1 + m_PVRDirectSampleCount: 32 + m_PVRSampleCount: 512 + m_PVRBounces: 2 + m_PVREnvironmentSampleCount: 256 + m_PVREnvironmentReferencePointCount: 2048 + m_PVRFilteringMode: 1 + m_PVRDenoiserTypeDirect: 1 + m_PVRDenoiserTypeIndirect: 1 + m_PVRDenoiserTypeAO: 1 + m_PVRFilterTypeDirect: 0 + m_PVRFilterTypeIndirect: 0 + m_PVRFilterTypeAO: 0 + m_PVREnvironmentMIS: 1 + m_PVRCulling: 1 + m_PVRFilteringGaussRadiusDirect: 1 + m_PVRFilteringGaussRadiusIndirect: 5 + m_PVRFilteringGaussRadiusAO: 2 + m_PVRFilteringAtrousPositionSigmaDirect: 0.5 + m_PVRFilteringAtrousPositionSigmaIndirect: 2 + m_PVRFilteringAtrousPositionSigmaAO: 1 + m_ExportTrainingData: 0 + m_TrainingDataDestination: TrainingData + m_LightProbeSampleCountMultiplier: 4 + m_LightingDataAsset: {fileID: 0} + m_LightingSettings: {fileID: 0} +--- !u!196 &4 +NavMeshSettings: + serializedVersion: 2 + m_ObjectHideFlags: 0 + m_BuildSettings: + serializedVersion: 3 + agentTypeID: 0 + agentRadius: 0.5 + agentHeight: 2 + agentSlope: 45 + agentClimb: 0.4 + ledgeDropHeight: 0 + maxJumpAcrossDistance: 0 + minRegionArea: 2 + manualCellSize: 0 + cellSize: 0.16666667 + manualTileSize: 0 + tileSize: 256 + buildHeightMesh: 0 + maxJobWorkers: 0 + preserveTilesOutsideBounds: 0 + debug: + m_Flags: 0 + m_NavMeshData: {fileID: 0} +--- !u!1 &552287861 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 552287864} + - component: {fileID: 552287863} + - component: {fileID: 552287862} + m_Layer: 0 + m_Name: Main Camera + m_TagString: MainCamera + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!81 &552287862 +AudioListener: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 552287861} + m_Enabled: 1 +--- !u!20 &552287863 +Camera: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 552287861} + m_Enabled: 1 + serializedVersion: 2 + m_ClearFlags: 1 + m_BackGroundColor: {r: 0.19215687, g: 0.3019608, b: 0.4745098, a: 0} + m_projectionMatrixMode: 1 + m_GateFitMode: 2 + m_FOVAxisMode: 0 + m_Iso: 200 + m_ShutterSpeed: 0.005 + m_Aperture: 16 + m_FocusDistance: 10 + m_FocalLength: 50 + m_BladeCount: 5 + m_Curvature: {x: 2, y: 11} + m_BarrelClipping: 0.25 + m_Anamorphism: 0 + m_SensorSize: {x: 36, y: 24} + m_LensShift: {x: 0, y: 0} + m_NormalizedViewPortRect: + serializedVersion: 2 + x: 0 + y: 0 + width: 1 + height: 1 + near clip plane: 0.3 + far clip plane: 1000 + field of view: 60 + orthographic: 1 + orthographic size: 5 + m_Depth: -1 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingPath: -1 + m_TargetTexture: {fileID: 0} + m_TargetDisplay: 0 + m_TargetEye: 3 + m_HDR: 1 + m_AllowMSAA: 1 + m_AllowDynamicResolution: 0 + m_ForceIntoRT: 0 + m_OcclusionCulling: 1 + m_StereoConvergence: 10 + m_StereoSeparation: 0.022 +--- !u!4 &552287864 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 552287861} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: -10} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1660057539 &9223372036854775807 +SceneRoots: + m_ObjectHideFlags: 0 + m_Roots: + - {fileID: 552287864} diff --git a/The 'Assets' folder of your Unity Prjct/Vehicle Noise Synthesizer/VNS Example UI Simple Scene.unity.meta b/The 'Assets' folder of your Unity Prjct/Vehicle Noise Synthesizer/VNS Example UI Simple Scene.unity.meta new file mode 100644 index 0000000..e785fec --- /dev/null +++ b/The 'Assets' folder of your Unity Prjct/Vehicle Noise Synthesizer/VNS Example UI Simple Scene.unity.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 41bc609117132e149862c8aa4e6a9ed1 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: From b2dbf98bdf075aea824fcc735f87f465db459593 Mon Sep 17 00:00:00 2001 From: Dan Date: Sat, 26 Oct 2024 00:47:10 +0200 Subject: [PATCH 3/3] VNS v1.5f Update WhatsNew - Vehicle Noise Synthesizer v1.5f Core Changes: - Replaced filename-based RPM detection with explicit RPM value input system - Added new EngineAudioClipData class for better audio clip management - Improved code organization with proper regions and documentation - Enhanced Inspector UI with better tooltips and grouping Audio Processing Improvements: - Added Animation Curve-based pitch control system - Implemented dynamic volume control through Animation Curves - Added new audio effect system with distortion and low-pass filtering - Improved muffling effect based on engine load New Features: - Added distortion effect with customizable intensity curve - Implemented advanced low-pass filter system for realistic muffling - Added combined load/RPM factor for more natural effect transitions - Enhanced audio priority system for better performance UI/UX Improvements: - Reorganized Inspector layout for better usability - Added comprehensive tooltips for all parameters - Improved parameter grouping and categorization - Enhanced debug value visibility Technical Improvements: - Optimized audio source management - Improved transition smoothing between audio states - Enhanced RPM range handling - Better audio effect component management Documentation: - Added detailed tooltips for all public parameters - Improved code comments and documentation - Added XML documentation for key methods - Updated usage instructions in Inspector Bug Fixes: - Fixed audio source creation redundancy - Corrected RPM range calculations - Improved audio transition smoothness - Fixed volume calculation issues --- .../Scripts/Core/VehicleNoiseSynthesizer.cs | 258 ++++++++++++------ 1 file changed, 173 insertions(+), 85 deletions(-) diff --git a/The 'Assets' folder of your Unity Prjct/Vehicle Noise Synthesizer/Scripts/Core/VehicleNoiseSynthesizer.cs b/The 'Assets' folder of your Unity Prjct/Vehicle Noise Synthesizer/Scripts/Core/VehicleNoiseSynthesizer.cs index a8227e4..948cd78 100644 --- a/The 'Assets' folder of your Unity Prjct/Vehicle Noise Synthesizer/Scripts/Core/VehicleNoiseSynthesizer.cs +++ b/The 'Assets' folder of your Unity Prjct/Vehicle Noise Synthesizer/Scripts/Core/VehicleNoiseSynthesizer.cs @@ -1,173 +1,261 @@ -/* -Several GitHub repositories inspire this but I lost their URLs - Please contact me if you're one of them in case of needing to add your personal website or username as a credit. -Written by ImDanOush (find me with this username @ImDanOush on IG, YT, TWTR,...) for "ATG Life Style and Vehicle Simulator" (@ATG_Simulator) -This entirely is freeware, See the repository's license section for more info. -*/ - using UnityEngine; using System.Collections.Generic; using UnityEngine.Audio; -using System; using System.Collections; -using static Unity.VisualScripting.Member; namespace AroundTheGroundSimulator { + [AddComponentMenu("ATG/Audio/Vehicle Noise Synthesizer")] + [RequireComponent(typeof(AudioSource))] + [HelpURL("https://github.com/ImDanOush/VehicleNoiseSynthesizer")] public class VehicleNoiseSynthesizer : MonoBehaviour { - // Control input manually + #region Debug Controls + [Header("Debug Controls")] + [Space(5)] + [Tooltip("Enable to manually control RPM and load values for testing")] public bool _debug = false; + [Range(100f, 9000f)] + [Tooltip("Test RPM value when debug mode is enabled")] public float debug_rpm = 800; + [Range(0.00f, 1.00f)] + [Tooltip("Test engine load value when debug mode is enabled")] public float debug_load = 1; + #endregion - [Space(7f)] - [Header("Granulator Properties")] - [Space(7f)] - // Shift final Pitch for fine-tuning (Optional) + #region Core Audio Settings + [Header("Core Audio Settings")] + [Space(10)] + [Tooltip("Fine-tune the overall pitch of engine sounds")] public float shiftPitch = 0; - // Change final volume for fine-tuning (Optional) + [Range(0.007f, 1.00f)] + [Tooltip("Master volume control for all engine sounds")] public float masterVolume = 1; - [Header("Engine Sound Curves")] + [Tooltip("Template AudioSource for copying base audio settings")] + public AudioSource audioSourceTemplate; + + [Tooltip("Optional mixer group for audio routing")] + public AudioMixerGroup mixer; + + [Tooltip("Type of engine sound (Intake, Engine, Exhaust, etc.)")] + public MixerType mixerType; + + [Tooltip("RPM difference between consecutive audio clips")] + public int rpm_deviation = 1000; + #endregion + + #region Sound Curves + [Header("Engine Sound Response Curves")] + [Space(10)] + [Tooltip("Controls how pitch changes with RPM (X: Normalized RPM, Y: Pitch multiplier)")] public AnimationCurve pitchCurve = new AnimationCurve( new Keyframe(0f, 0.6f), new Keyframe(1f, 1.2f) ); + [Tooltip("Controls how volume changes with RPM (X: Normalized RPM, Y: Volume multiplier)")] public AnimationCurve volumeCurve = new AnimationCurve( new Keyframe(0f, 0.5f), new Keyframe(1f, 1f) ); + #endregion - public AudioSource audioSourceTemplate; - public AudioMixerGroup mixer; // Audio Mixer Group assigned to the audio sources of this script - optional - public MixerType mixerType; // Which one of the three default types should be used? (see the audio mixer in the demo, there are Engine, Intake and Exhaust ones by default) - - public int rpm_deviation = 1000; // the constant difference of the rpm value of audio clips, e.g audio clip 1 has the audio of an engine at 1000 rpm, audio clip 2 has has the audio of an engine at 2500 rpm. so the value should be close or a bit less than 1500 - - // - - [Header("Audio Effect Curves")] + #region Audio Effect Settings + [Header("Audio Effects Configuration")] + [Space(10)] + [Tooltip("Controls distortion amount based on RPM and load")] public AnimationCurve distortionCurve = new AnimationCurve( new Keyframe(0f, 0f), new Keyframe(0.7f, 0.3f), new Keyframe(1f, 0.5f) ); - [Header("Audio Effect Parameters")] [Range(0f, 1f)] + [Tooltip("Overall intensity of the distortion effect")] public float distortionIntensity = 0.5f; + [Range(0f, 1f)] + [Tooltip("Intensity of the muffling effect when engine load decreases")] public float mufflingIntensity = 0.5f; [Header("Low Pass Filter")] + [Space(5)] + [Tooltip("Controls frequency cutoff based on load (X: Load, Y: Cutoff frequency)")] public AnimationCurve lowPassCurve = new AnimationCurve( - new Keyframe(1f, 1000f), // Heavy filtering - new Keyframe(0f, 22000f) // Full frequency range + new Keyframe(1f, 1000f), + new Keyframe(0f, 22000f) ); + [Range(0f, 1f)] + [Tooltip("Overall intensity of the low pass filter effect")] public float lowPassIntensity = 0.5f; - - private AudioLowPassFilter[] acceleratingLowPass; - private AudioLowPassFilter[] deceleratingLowPass; - private AudioDistortionFilter[] acceleratingDistortion; - private AudioDistortionFilter[] deceleratingDistortion; - - // - + #endregion + #region Volume and Audio Clip Settings [System.Serializable] public class EngineAudioClipData { + [Tooltip("Audio clip containing engine sound")] public AudioClip audioClip; + + [Tooltip("RPM value at which this audio clip should play")] + [Range(0, 10000)] public int rpmValue; - } - [Tooltip("Audio clips for engine acceleration with their respective RPM values")] + [Tooltip("Optional description for this audio clip")] + public string description; + } + [Header("Audio Clip Configuration")] + [Space(10)] + [SerializeField] + [Tooltip("List of audio clips for engine acceleration, each with its corresponding RPM value")] public List acceleratingSounds = new List(); - [Tooltip("[Optional] Audio clips for engine deceleration with their respective RPM values")] + + [SerializeField] + [Tooltip("Optional list of audio clips for engine deceleration, each with its corresponding RPM value")] public List deceleratingSounds = new List(); - // Mimimum and Maximum values of volumes - [Tooltip("If there is no decelrating sound clips, the accelerating sound clip with the lowest RPM value is chosen and this will be its default volume when it is idle.")] + [Header("Volume Configuration")] + [Space(10)] + [Tooltip("Default volume when engine is idle (used when no deceleration clips are present)")] [Range(0.05f, 1.00f)] public float idleAccVolume = 0.1f; - [Tooltip("If max volume is set to 0 that means the audio volum is left as is.")] + + [Tooltip("Maximum volume for acceleration sounds (0 means no limit)")] [Range(0.00f, 1.00f)] public float maxVolumeAcc = 0.4f; + + [Tooltip("Maximum volume for deceleration sounds")] [Range(0.00f, 1.00f)] public float maxVolumeDcc = 0.1f; - [Space(7f)] - [Header("Advanced Granulator Properties")] - [Space(7f)] - // How smooth audioclips and their volume value can change? + [Header("Transition Settings")] + [Space(10)] + [Tooltip("How smoothly audio clips and volume changes occur")] + [Range(1f, 50f)] public float transitionTime = 20f; - // How smooth accelerating audioclips and their pitch value can change? suggested to use the same value as transitionTime. + + [Tooltip("Smoothness of pitch changes during acceleration")] + [Range(1f, 50f)] public float acPitchTransitionTime = 20f; - // How smooth decelerating audioclips and their pitch value can change? suggested to use the same value as transitionTime. + + [Tooltip("Smoothness of pitch changes during deceleration")] + [Range(1f, 50f)] public float dcPitchTransitionTime = 20f; - // Adjust the pitch of accelerating sound clip for fine-tuning + #endregion + + #region Fine-Tuning Parameters + [Header("Fine-Tuning")] + [Space(10)] + [Tooltip("Fine-tune pitch for acceleration sounds")] + [Range(-1f, 1f)] public float acPitchTrim = 0; - // Adjust the pitch of accelerating sound clip for fine-tuning + + [Tooltip("Fine-tune pitch for deceleration sounds")] + [Range(-1f, 1f)] public float dcPitchTrim = 0; - // Add random pitch + + [Tooltip("Add random variation to pitch")] [Range(-0.060f, 0.060f)] public float rndmPitch = 0; - // Used for the table of pitches, if the maximum RPM of your engine is more than 10000 set it something more than that. + + [Tooltip("Maximum theoretical RPM value for calculations")] + [Range(1000f, 20000f)] public float maximumTheoricalRPM = 10000; + + [Tooltip("Base pitch value when engine is idle")] + [Range(0.5f, 2f)] public float idlePitch = 1; + #endregion + #region Internal State Variables + [Header("Internal State")] + [Space(10)] + [SerializeField] + [Tooltip("Current engine RPM")] + private float _rpm; - //[HideInInspector] - public float rpm - { - get; internal set; // sets the rpm value based on one of the inputs like the provided "AudioGranulatorNWHVehiclePhysics2" class - } - //[HideInInspector] - public float load - { - get; internal set; // sets the load value based on one of the inputs like the provided "AudioGranulatorNWHVehiclePhysics2" class - } + [SerializeField] + [Tooltip("Current engine load")] + private float _load; - [Space(47f)] - [Header("[Read-Only] Debug Values")] - [Space(7f)] - // Table of audio clip ranges for fading based on the rpm value [SerializeField] - float[] _AcMin_rTable; + [Tooltip("Maximum RPM of the engine")] + private float _maxRpm; + [SerializeField] - float[] _AcNormal_rTable; + [Tooltip("Engine state (on/off)")] + private bool _isOn; + [SerializeField] - float[] _AcMax_rTable; + [Tooltip("Idle RPM value")] + private float _idleRpm; + [SerializeField] - float[] _DcMin_rTable; + [Tooltip("Previous frame RPM value")] + private float l_r; + [SerializeField] - float[] _DcNormal_rTable; + [Tooltip("Final pitch value after all modifications")] + private float _finalPitch = 1f; + [SerializeField] - float[] _DcMax_rTable; + [Tooltip("Current volume for acceleration sounds")] + private float _finalAccVol = 0; + [SerializeField] - bool _nonDecelerateAudiosMode = true; + [Tooltip("Current volume for deceleration sounds")] + private float _finalDecVol = 0; + #endregion + + #region Audio Processing Tables + [Header("Audio Processing Tables")] + [Space(10)] + [SerializeField] + [Tooltip("Minimum RPM values for acceleration clips")] + private float[] _AcMin_rTable; + + [SerializeField] + [Tooltip("Normal RPM values for acceleration clips")] + private float[] _AcNormal_rTable; + + [SerializeField] + [Tooltip("Maximum RPM values for acceleration clips")] + private float[] _AcMax_rTable; + [SerializeField] - float _rpm; // current engine rpm + [Tooltip("Minimum RPM values for deceleration clips")] + private float[] _DcMin_rTable; + [SerializeField] - float _load; // current engine load + [Tooltip("Normal RPM values for deceleration clips")] + private float[] _DcNormal_rTable; + [SerializeField] - float _maxRpm; // max rpm of the engine + [Tooltip("Maximum RPM values for deceleration clips")] + private float[] _DcMax_rTable; + [SerializeField] - float _RangeDivider = 1; // scale the range of which an audio clip fades out/in to another one per its audio clip type - accelerating/decelerating - - // used for calculations - bool _isOn = false; //is the car turned on? - float _idleRpm; // used for correcting idle audio volume level - float l_r; // the rpm value in previous frame - float _finalAccVol = 0; // values of audio clips when the vehicle is accelerating - float _finalDecVol = 0; // values of audio clips wheb the vehicle is decelerating - [SerializeField] float _finalPitch = 1f; // final raw pitch value + [Tooltip("True if no deceleration audio clips are provided")] + private bool _nonDecelerateAudiosMode = true; + + [SerializeField] + [Tooltip("Scale factor for audio clip fade ranges")] + private float _RangeDivider = 1; + #endregion + + #region Audio Sources private List _accelerateAudios; private List _decelerateAudios; - float vol; + private float vol; + #endregion + + #region Public Properties + public float rpm { get; internal set; } + public float load { get; internal set; } + #endregion public enum MixerType {