/* --------------------------------------- * Author: Martin Pane (martintayx@gmail.com) (@martinTayx) * Contributors: https://github.com/Tayx94/graphy/graphs/contributors * Project: Graphy - Ultimate Stats Monitor * Date: 15-Dec-17 * Studio: Tayx * * Git repo: https://github.com/Tayx94/graphy * * This project is released under the MIT license. * Attribution is not required, but it is always welcomed! * -------------------------------------*/ using UnityEngine; using UnityEngine.SceneManagement; namespace Tayx.Graphy.Audio { /// /// Note: this class only works with Unity's AudioListener. /// If you're using a custom audio engine (like FMOD or WWise) it won't work, /// although you can always adapt it. /// public class G_AudioMonitor : MonoBehaviour { #region Variables -> Private private const float m_refValue = 1f; private GraphyManager m_graphyManager = null; private AudioListener m_audioListener = null; private GraphyManager.LookForAudioListener m_findAudioListenerInCameraIfNull = GraphyManager.LookForAudioListener.ON_SCENE_LOAD; private FFTWindow m_FFTWindow = FFTWindow.Blackman; private int m_spectrumSize = 512; #endregion #region Properties -> Public /// /// Current audio spectrum from the specified AudioListener. /// public float[] Spectrum { get; private set; } /// /// Highest audio spectrum from the specified AudioListener in the last few seconds. /// public float[] SpectrumHighestValues { get; private set; } /// /// Maximum DB registered in the current spectrum. /// public float MaxDB { get; private set; } /// /// Returns true if there is a reference to the audio listener. /// public bool SpectrumDataAvailable => m_audioListener != null; #endregion #region Methods -> Unity Callbacks private void Awake() { Init(); } private void Update() { if( m_audioListener != null ) { // Use this data to calculate the dB value AudioListener.GetOutputData( Spectrum, 0 ); float sum = 0; for( int i = 0; i < Spectrum.Length; i++ ) { sum += Spectrum[ i ] * Spectrum[ i ]; // sum squared samples } float rmsValue = Mathf.Sqrt( sum / Spectrum.Length ); // rms = square root of average MaxDB = 20 * Mathf.Log10( rmsValue / m_refValue ); // calculate dB if( MaxDB < -80 ) MaxDB = -80; // clamp it to -80dB min // Use this data to draw the spectrum in the graphs AudioListener.GetSpectrumData( Spectrum, 0, m_FFTWindow ); for( int i = 0; i < Spectrum.Length; i++ ) { // Update the highest value if its lower than the current one if( Spectrum[ i ] > SpectrumHighestValues[ i ] ) { SpectrumHighestValues[ i ] = Spectrum[ i ]; } // Slowly lower the value else { SpectrumHighestValues[ i ] = Mathf.Clamp ( value: SpectrumHighestValues[ i ] - SpectrumHighestValues[ i ] * Time.deltaTime * 2, min: 0, max: 1 ); } } } else if( m_audioListener == null && m_findAudioListenerInCameraIfNull == GraphyManager.LookForAudioListener.ALWAYS ) { m_audioListener = FindAudioListener(); } } private void OnDestroy() { UnityEngine.SceneManagement.SceneManager.sceneLoaded -= OnSceneLoaded; } #endregion #region Methods -> Public public void UpdateParameters() { m_findAudioListenerInCameraIfNull = m_graphyManager.FindAudioListenerInCameraIfNull; m_audioListener = m_graphyManager.AudioListener; m_FFTWindow = m_graphyManager.FftWindow; m_spectrumSize = m_graphyManager.SpectrumSize; if( m_audioListener == null && m_findAudioListenerInCameraIfNull != GraphyManager.LookForAudioListener.NEVER ) { m_audioListener = FindAudioListener(); } Spectrum = new float[m_spectrumSize]; SpectrumHighestValues = new float[m_spectrumSize]; } /// /// Converts spectrum values to decibels using logarithms. /// /// /// public float lin2dB( float linear ) { return Mathf.Clamp( Mathf.Log10( linear ) * 20.0f, -160.0f, 0.0f ); } /// /// Normalizes a value in decibels between 0-1. /// /// /// public float dBNormalized( float db ) { return (db + 160f) / 160f; } #endregion #region Methods -> Private /// /// Tries to find an audio listener in the main camera. /// private AudioListener FindAudioListener() { Camera mainCamera = Camera.main; if( mainCamera != null && mainCamera.TryGetComponent( out AudioListener audioListener ) ) { return audioListener; } return null; } private void OnSceneLoaded( Scene scene, LoadSceneMode loadSceneMode ) { if( m_findAudioListenerInCameraIfNull == GraphyManager.LookForAudioListener.ON_SCENE_LOAD ) { m_audioListener = FindAudioListener(); } } private void Init() { m_graphyManager = transform.root.GetComponentInChildren(); UpdateParameters(); UnityEngine.SceneManagement.SceneManager.sceneLoaded += OnSceneLoaded; } #endregion } }