CubismAudioMouthInput.cs 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. /**
  2. * Copyright(c) Live2D Inc. All rights reserved.
  3. *
  4. * Use of this source code is governed by the Live2D Open Software license
  5. * that can be found at https://www.live2d.com/eula/live2d-open-software-license-agreement_en.html.
  6. */
  7. using UnityEngine;
  8. namespace Live2D.Cubism.Framework.MouthMovement
  9. {
  10. /// <summary>
  11. /// Real-time <see cref="CubismMouthController"/> input from <see cref="AudioSource"/>s.
  12. /// </summary>
  13. [RequireComponent(typeof(CubismMouthController))]
  14. public sealed class CubismAudioMouthInput : MonoBehaviour
  15. {
  16. /// <summary>
  17. /// Audio source to sample.
  18. /// </summary>
  19. [SerializeField]
  20. public AudioSource AudioInput;
  21. /// <summary>
  22. /// Sampling quality.
  23. /// </summary>
  24. [SerializeField]
  25. public CubismAudioSamplingQuality SamplingQuality;
  26. /// <summary>
  27. /// Audio gain.
  28. /// </summary>
  29. [Range(1.0f, 10.0f)]
  30. public float Gain = 1.0f;
  31. /// <summary>
  32. /// Smoothing.
  33. /// </summary>
  34. [Range(0.0f, 1.0f)]
  35. public float Smoothing;
  36. /// <summary>
  37. /// Current samples.
  38. /// </summary>
  39. private float[] Samples { get; set; }
  40. /// <summary>
  41. /// Last root mean square.
  42. /// </summary>
  43. private float LastRms { get; set; }
  44. /// <summary>
  45. /// Buffer for <see cref="Mathf.SmoothDamp(float, float, ref float, float)"/> velocity.
  46. /// </summary>
  47. // ReSharper disable once InconsistentNaming
  48. private float VelocityBuffer;
  49. /// <summary>
  50. /// Targeted <see cref="CubismMouthController"/>.
  51. /// </summary>
  52. private CubismMouthController Target { get; set; }
  53. /// <summary>
  54. /// True if instance is initialized.
  55. /// </summary>
  56. private bool IsInitialized
  57. {
  58. get { return Samples != null; }
  59. }
  60. /// <summary>
  61. /// Makes sure instance is initialized.
  62. /// </summary>
  63. private void TryInitialize()
  64. {
  65. // Return early if already initialized.
  66. if (IsInitialized)
  67. {
  68. return;
  69. }
  70. // Initialize samples buffer.
  71. switch (SamplingQuality)
  72. {
  73. case (CubismAudioSamplingQuality.VeryHigh):
  74. {
  75. Samples = new float[256];
  76. break;
  77. }
  78. case (CubismAudioSamplingQuality.Maximum):
  79. {
  80. Samples = new float[512];
  81. break;
  82. }
  83. default:
  84. {
  85. Samples = new float[256];
  86. break;
  87. }
  88. }
  89. // Cache target.
  90. Target = GetComponent<CubismMouthController>();
  91. }
  92. #region Unity Event Handling
  93. /// <summary>
  94. /// Samples audio input and applies it to mouth controller.
  95. /// </summary>
  96. private void Update()
  97. {
  98. // 'Fail' silently.
  99. if (AudioInput == null)
  100. {
  101. return;
  102. }
  103. // Sample audio.
  104. var total = 0f;
  105. AudioInput.GetOutputData(Samples, 0);
  106. for (var i = 0; i < Samples.Length; ++i)
  107. {
  108. var sample = Samples[i];
  109. total += (sample * sample);
  110. }
  111. // Compute root mean square over samples.
  112. var rms = Mathf.Sqrt(total / Samples.Length) * Gain;
  113. // Clamp root mean square.
  114. rms = Mathf.Clamp(rms, 0.0f, 1.0f);
  115. // Smooth rms.
  116. rms = Mathf.SmoothDamp(LastRms, rms, ref VelocityBuffer, Smoothing * 0.1f);
  117. // Set rms as mouth opening and store it for next evaluation.
  118. Target.MouthOpening = rms;
  119. LastRms = rms;
  120. }
  121. /// <summary>
  122. /// Initializes instance.
  123. /// </summary>
  124. private void OnEnable()
  125. {
  126. TryInitialize();
  127. }
  128. #endregion
  129. }
  130. }