/** * 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 } }