AsteroidGame/Assets/Plugins/Graphy/Runtime/Audio/G_AudioMonitor.cs

211 lines
6.4 KiB
C#

/* ---------------------------------------
* 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
{
/// <summary>
/// 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.
/// </summary>
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
/// <summary>
/// Current audio spectrum from the specified AudioListener.
/// </summary>
public float[] Spectrum { get; private set; }
/// <summary>
/// Highest audio spectrum from the specified AudioListener in the last few seconds.
/// </summary>
public float[] SpectrumHighestValues { get; private set; }
/// <summary>
/// Maximum DB registered in the current spectrum.
/// </summary>
public float MaxDB { get; private set; }
/// <summary>
/// Returns true if there is a reference to the audio listener.
/// </summary>
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];
}
/// <summary>
/// Converts spectrum values to decibels using logarithms.
/// </summary>
/// <param name="linear"></param>
/// <returns></returns>
public float lin2dB( float linear )
{
return Mathf.Clamp( Mathf.Log10( linear ) * 20.0f, -160.0f, 0.0f );
}
/// <summary>
/// Normalizes a value in decibels between 0-1.
/// </summary>
/// <param name="db"></param>
/// <returns></returns>
public float dBNormalized( float db )
{
return (db + 160f) / 160f;
}
#endregion
#region Methods -> Private
/// <summary>
/// Tries to find an audio listener in the main camera.
/// </summary>
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<GraphyManager>();
UpdateParameters();
UnityEngine.SceneManagement.SceneManager.sceneLoaded += OnSceneLoaded;
}
#endregion
}
}