AudioClipAudioSource.cs 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. /*
  2. * Copyright (c) Meta Platforms, Inc. and affiliates.
  3. * All rights reserved.
  4. *
  5. * This source code is licensed under the license found in the
  6. * LICENSE file in the root directory of this source tree.
  7. */
  8. using System;
  9. using System.Collections;
  10. using System.Collections.Generic;
  11. using Meta.WitAi;
  12. using Meta.WitAi.Data;
  13. using Meta.WitAi.Interfaces;
  14. using UnityEngine;
  15. public class AudioClipAudioSource : MonoBehaviour, IAudioInputSource
  16. {
  17. [SerializeField] private AudioSource _audioSource;
  18. [SerializeField] private List<AudioClip> _audioClips;
  19. [Tooltip("If true, the associated clips will be played again from the beginning with multiple requests after the clip queue has been exhausted.")]
  20. [SerializeField] private bool _loopRequests;
  21. private bool _isRecording;
  22. private Queue<int> _audioQueue = new Queue<int>();
  23. private int clipIndex = 0;
  24. private float[] activeClip;
  25. private int activeClipIndex;
  26. private float[] activeClipBuffer = new float[0];
  27. private List<float[]> clipData = new List<float[]>();
  28. private void Start()
  29. {
  30. foreach (var clip in _audioClips)
  31. {
  32. AddClipData(clip);
  33. VLog.D($"Added {clip.name} to queue");
  34. }
  35. }
  36. private void SendSample(float[] sample)
  37. {
  38. var len = Math.Min(_audioQueue.Dequeue(), activeClip.Length - activeClipIndex);
  39. try
  40. {
  41. VLog.D("Sending length: " + len);
  42. activeClipBuffer = new float[len];
  43. Array.Copy(activeClip, activeClipIndex, activeClipBuffer, 0, len);
  44. activeClipIndex += len;
  45. }
  46. catch (ArgumentException e)
  47. {
  48. VLog.D(e);
  49. }
  50. var max = float.MinValue;
  51. foreach (var f in activeClipBuffer)
  52. {
  53. max = Mathf.Max(f, max);
  54. }
  55. OnSampleReady?.Invoke(activeClipBuffer.Length, activeClipBuffer, max);
  56. }
  57. public event Action OnStartRecording;
  58. public event Action OnStartRecordingFailed;
  59. public event Action<int, float[], float> OnSampleReady;
  60. public event Action OnStopRecording;
  61. public void StartRecording(int sampleLen)
  62. {
  63. if (_isRecording)
  64. {
  65. OnStartRecordingFailed?.Invoke();
  66. return;
  67. }
  68. _isRecording = true;
  69. if (clipIndex >= _audioClips.Count && _loopRequests)
  70. {
  71. clipIndex = 0;
  72. }
  73. if (clipIndex < _audioClips.Count)
  74. {
  75. activeClip = clipData[clipIndex];
  76. activeClipIndex = 0;
  77. VLog.D($"Starting clip {clipIndex}");
  78. _isRecording = true;
  79. VLog.D($"Playing {_audioClips[clipIndex].name}");
  80. _audioSource.PlayOneShot(_audioClips[clipIndex]);
  81. StartCoroutine(ProcessClip(_audioClips[clipIndex], clipData[clipIndex]));
  82. OnStartRecording?.Invoke();
  83. }
  84. else
  85. {
  86. OnStartRecordingFailed?.Invoke();
  87. }
  88. }
  89. private IEnumerator ProcessClip(AudioClip clip, float[] clipData)
  90. {
  91. int chunkSize = 0;
  92. for (int index = 0; index < clipData.Length; index += chunkSize)
  93. {
  94. chunkSize = (int) (16000 * Time.deltaTime);
  95. int len = Math.Min(chunkSize, clipData.Length - index);
  96. var data = new float[chunkSize];
  97. Array.Copy(clipData, index, data, 0, len);
  98. var max = float.MinValue;
  99. foreach (var f in data)
  100. {
  101. max = Mathf.Max(f, max);
  102. }
  103. VLog.D($"Sending {index}/{clipData.Length} [{data.Length}] samples with a max volume of {max}");
  104. OnSampleReady?.Invoke(data.Length, data, max);
  105. yield return null;
  106. }
  107. StopRecording();
  108. clipIndex++;
  109. }
  110. public void StopRecording()
  111. {
  112. _isRecording = false;
  113. OnStopRecording?.Invoke();
  114. }
  115. public bool IsRecording => _isRecording;
  116. public AudioEncoding AudioEncoding => new AudioEncoding();
  117. public bool IsInputAvailable => true;
  118. public void CheckForInput()
  119. {
  120. }
  121. public bool SetActiveClip(string clipName)
  122. {
  123. int index = _audioClips.FindIndex(0, (AudioClip clip) => {
  124. if (clip.name == clipName)
  125. {
  126. return true;
  127. }
  128. return false;
  129. });
  130. if (index < 0 || index >= _audioClips.Count)
  131. {
  132. VLog.D($"Couldn't find clip {clipName}");
  133. return false;
  134. }
  135. clipIndex = index;
  136. return true;
  137. }
  138. public void AddClip(AudioClip clip)
  139. {
  140. _audioClips.Add(clip);
  141. AddClipData(clip);
  142. VLog.D($"Clip added {clip.name}");
  143. }
  144. private void AddClipData(AudioClip clip)
  145. {
  146. var samples = new float[clip.samples];
  147. clip.GetData(samples, 0);
  148. clipData.Add(samples);
  149. }
  150. }