Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- using System.Collections;
- using System.Collections.Generic;
- using UnityEditor;
- using UnityEngine;
- using UnityEngine.UIElements;
- namespace BrokenWings
- {
- [RequireComponent(typeof(AudioSource))]
- public class LipSync : MonoBehaviour
- {
- private AudioSource audioSource;
- private float[] clipSampleData;
- private const int sampleDataLength = 1024;
- private float clipLoudness = 0.0f;
- [SerializeField] private Transform lipsObject;
- [SerializeField] private AudioClip[] sentences;
- [SerializeField][Range(0.01f, 5.0f)] private float sensitivity = 1.0f;
- private int sentenceTracker = 0;
- [Tooltip("This is used to activate the speech, once activated the speech will start and the system will deactivate it, so you can activate it again for the next sentence.")]
- [SerializeField] GameObject activator;
- [SerializeField] GameObject brows;
- Animator browsAnim;
- [Tooltip("Eyes Game Object, to be set by hand, Note that the eyes are scaled on Y axis while the mouth on Z!")]
- [SerializeField] GameObject eyes;
- [SerializeField] float eyeOpene = 1f;
- [SerializeField] float eyeClose = 0.01f;
- [Tooltip("Random interval for the next blink in second")]
- [Range(2f, 20f)]
- [SerializeField] float blinkInterval;
- [SerializeField] private float blinkDuration = 0.1f;
- private float blinkTimer = 0f;
- private bool isBlinking = false;
- public enum EmotionState
- {
- Idle = 0,
- RiseBrow = 1,
- Suprise = 2,
- Fear = 3,
- Anger = 4,
- Happy = 5 // This should Rise the bow and squeeze the eyes at 60%
- }
- public EmotionState currentEmotion = EmotionState.Idle;
- public EmotionState CurrentEmotion
- {
- get { return currentEmotion; }
- set
- {
- currentEmotion = value;
- browsAnim.SetInteger("EmotionalState", (int)currentEmotion);
- }
- }
- private bool _play = false;
- public bool Play
- {
- get { return _play; }
- set
- {
- _play = value;
- }
- }
- private enum ScalingAxis
- {
- X,
- Y,
- Z
- }
- [Tooltip("The axis that need to be scaled")]
- [SerializeField] private ScalingAxis selectedAxis = ScalingAxis.Z;
- // Sets the value to maximize and minimize the Y scale for the lips
- [SerializeField] private float minScale = 0.13f;
- [SerializeField] private float maxScale = 1f;
- private float maxLoudness = 0f;
- private void Start()
- {
- audioSource = GetComponent<AudioSource>();
- clipSampleData = new float[sampleDataLength];
- sentenceTracker = 0;
- audioSource.Stop();
- // Brows
- if (brows == null)
- Debug.LogError("!!! NO BROWS !!! \n " + gameObject.name + "Didn't have any brows assigned!");
- browsAnim = brows.GetComponent<Animator>();
- // Eyes
- if (eyes == null)
- Debug.LogError("!!! NO EYES !!! \n " + gameObject.name + "Didn't have any eyes assigned!");
- }
- private void Update()
- {
- if(activator.activeSelf)
- {
- activator.SetActive(false);
- Play = true;
- }
- if(_play)
- {
- if(sentenceTracker >= sentences.Length) sentenceTracker = 0;
- audioSource.clip = sentences[sentenceTracker];
- audioSource.Play();
- _play = false;
- sentenceTracker++;
- }
- if(audioSource.isPlaying)
- MoveLips();
- else
- {
- IsBlinking();
- }
- }
- private void MoveLips()
- {
- if (audioSource.isPlaying)
- {
- audioSource.clip.GetData(clipSampleData, audioSource.timeSamples);
- if (audioSource.timeSamples > 0)
- {
- float sumLoudness = 0f;
- foreach (var Sample in clipSampleData)
- {
- sumLoudness += Mathf.Abs(Sample);
- }
- // Get the average loudness
- clipLoudness = sumLoudness / clipSampleData.Length;
- // Aggiorna il valore massimo di loudness se necessario
- if (clipLoudness > maxLoudness)
- {
- maxLoudness = clipLoudness;
- }
- // Normalize the loudness to the maximum observed value
- clipLoudness /= maxLoudness;
- // Map normalized loudness within the Y scale
- float scaleZValue = Mathf.Lerp(minScale, maxScale, clipLoudness);
- // Debug.Log(clipLoudness);
- // Close the mouth when clipLoudness is low.
- if (clipLoudness <= 0) scaleZValue = minScale;
- // Map normalized loudness within the selected scaling axis
- float scaleValue = 0f;
- // Calculate the scaled sensitivity based on the maximum observed loudness
- float scaledSensitivity = sensitivity * maxLoudness;
- switch (selectedAxis)
- {
- case ScalingAxis.X:
- scaleValue = Mathf.Lerp(minScale, maxScale, clipLoudness * scaledSensitivity);
- lipsObject.localScale = new Vector3(scaleValue, lipsObject.localScale.y, lipsObject.localScale.z);
- break;
- case ScalingAxis.Y:
- scaleValue = Mathf.Lerp(minScale, maxScale, clipLoudness);
- lipsObject.localScale = new Vector3(lipsObject.localScale.x, scaleValue, lipsObject.localScale.z);
- break;
- case ScalingAxis.Z:
- scaleValue = Mathf.Lerp(minScale, maxScale, clipLoudness);
- lipsObject.localScale = new Vector3(lipsObject.localScale.x, lipsObject.localScale.y, scaleValue);
- break;
- }
- lipsObject.localScale = new Vector3(lipsObject.localScale.x, lipsObject.localScale.y, scaleZValue);
- }
- }
- }
- public void BlinkEyes(float ec, float eo)
- {
- float randomScale = Random.Range(ec, eo);
- Vector3 newScale = eyes.transform.localScale;
- newScale.y = randomScale;
- eyes.transform.localScale = newScale;
- }
- private void ResetEyeScale()
- {
- Vector3 newScale = eyes.transform.localScale;
- newScale.y = 1f;
- eyes.transform.localScale = newScale;
- }
- private void IsBlinking()
- {
- if (!isBlinking)
- {
- // Generate a random time interval for the next blink
- float randomInterval = Random.Range(1f, blinkInterval);
- blinkTimer += Time.deltaTime;
- if (blinkTimer >= randomInterval)
- {
- // Start blinking
- isBlinking = true;
- blinkTimer = 0f;
- BlinkEyes(eyeClose, eyeOpene);
- }
- }
- else
- {
- // Continue blinking for the blink duration
- blinkTimer += Time.deltaTime;
- if (blinkTimer >= blinkDuration)
- {
- // Stop blinking
- isBlinking = false;
- blinkTimer = 0f;
- ResetEyeScale();
- }
- }
- }
- public void SetSentence(int sentence)
- {
- sentenceTracker = sentence;
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment