/**
* Copyright(c) Live2D Inc. All rights reserved.
*
* Use of this source code is governed by the Live2D Open Software license
* that can be found at https://www.live2d.com/eula/live2d-open-software-license-agreement_en.html.
*/
using UnityEngine;
namespace Live2D.Cubism.Framework.MouthMovement
{
///
/// Real-time input from s.
///
[RequireComponent(typeof(CubismMouthController))]
public sealed class CubismAudioMouthInput : MonoBehaviour
{
///
/// Audio source to sample.
///
[SerializeField]
public AudioSource AudioInput;
///
/// Sampling quality.
///
[SerializeField]
public CubismAudioSamplingQuality SamplingQuality;
///
/// Audio gain.
///
[Range(1.0f, 10.0f)]
public float Gain = 1.0f;
///
/// Smoothing.
///
[Range(0.0f, 1.0f)]
public float Smoothing;
///
/// Current samples.
///
private float[] Samples { get; set; }
///
/// Last root mean square.
///
private float LastRms { get; set; }
///
/// Buffer for velocity.
///
// ReSharper disable once InconsistentNaming
private float VelocityBuffer;
///
/// Targeted .
///
private CubismMouthController Target { get; set; }
///
/// True if instance is initialized.
///
private bool IsInitialized
{
get { return Samples != null; }
}
///
/// Makes sure instance is initialized.
///
private void TryInitialize()
{
// Return early if already initialized.
if (IsInitialized)
{
return;
}
// Initialize samples buffer.
switch (SamplingQuality)
{
case (CubismAudioSamplingQuality.VeryHigh):
{
Samples = new float[256];
break;
}
case (CubismAudioSamplingQuality.Maximum):
{
Samples = new float[512];
break;
}
default:
{
Samples = new float[256];
break;
}
}
// Cache target.
Target = GetComponent();
}
#region Unity Event Handling
///
/// Samples audio input and applies it to mouth controller.
///
private void Update()
{
// 'Fail' silently.
if (AudioInput == null)
{
return;
}
// Sample audio.
var total = 0f;
AudioInput.GetOutputData(Samples, 0);
for (var i = 0; i < Samples.Length; ++i)
{
var sample = Samples[i];
total += (sample * sample);
}
// Compute root mean square over samples.
var rms = Mathf.Sqrt(total / Samples.Length) * Gain;
// Clamp root mean square.
rms = Mathf.Clamp(rms, 0.0f, 1.0f);
// Smooth rms.
rms = Mathf.SmoothDamp(LastRms, rms, ref VelocityBuffer, Smoothing * 0.1f);
// Set rms as mouth opening and store it for next evaluation.
Target.MouthOpening = rms;
LastRms = rms;
}
///
/// Initializes instance.
///
private void OnEnable()
{
TryInitialize();
}
#endregion
}
}