UnityAudioCapture.cs 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. using UnityEngine;
  2. using System.Collections;
  3. using System.Runtime.InteropServices;
  4. //-----------------------------------------------------------------------------
  5. // Copyright 2012-2017 RenderHeads Ltd. All rights reserved.
  6. //-----------------------------------------------------------------------------
  7. namespace RenderHeads.Media.AVProMovieCapture
  8. {
  9. /// <summary>
  10. /// Captures audio from an audio listener and adds it to a buffer
  11. /// The AVPro Movie Capture plugin pulls the data from this buffer and flushes it periodically
  12. /// </summary>
  13. [RequireComponent(typeof(AudioListener))]
  14. [AddComponentMenu("AVPro Movie Capture/Unity Audio Capture (requires AudioListener)", 500)]
  15. public class UnityAudioCapture : MonoBehaviour
  16. {
  17. [SerializeField]
  18. private bool _debugLogging = false;
  19. private const int BufferSize = 16;
  20. private float[] _buffer = new float[0];
  21. private float[] _readBuffer = new float[0];
  22. private int _bufferIndex;
  23. private GCHandle _bufferHandle;
  24. private int _numChannels;
  25. private int _overflowCount;
  26. private object _lockObject = new object();
  27. public float[] Buffer { get { return _readBuffer; } }
  28. public int BufferLength { get { return _bufferIndex; } }
  29. public int NumChannels { get { return _numChannels; } }
  30. public System.IntPtr BufferPtr { get { return _bufferHandle.AddrOfPinnedObject(); } }
  31. public int OverflowCount
  32. {
  33. get { return _overflowCount; }
  34. }
  35. void OnEnable()
  36. {
  37. int bufferLength = 0;
  38. int numBuffers = 0;
  39. AudioSettings.GetDSPBufferSize(out bufferLength, out numBuffers);
  40. #if UNITY_5_4_OR_NEWER || UNITY_5
  41. _numChannels = GetNumChannels(AudioSettings.driverCapabilities);
  42. //if (AudioSettings.speakerMode != AudioSpeakerMode.Raw &&
  43. if (AudioSettings.speakerMode < AudioSettings.driverCapabilities)
  44. {
  45. _numChannels = GetNumChannels(AudioSettings.speakerMode);
  46. }
  47. if (_debugLogging)
  48. {
  49. Debug.Log(string.Format("[UnityAudioCapture] SampleRate: {0}hz SpeakerMode: {1} BestDriverMode: {2} (DSP using {3} buffers of {4} bytes using {5} channels)", AudioSettings.outputSampleRate, AudioSettings.speakerMode.ToString(), AudioSettings.driverCapabilities.ToString(), numBuffers, bufferLength, _numChannels));
  50. }
  51. #else
  52. _numChannels = GetNumChannels(AudioSettings.driverCaps);
  53. if (AudioSettings.speakerMode != AudioSpeakerMode.Raw &&
  54. AudioSettings.speakerMode < AudioSettings.driverCaps)
  55. {
  56. _numChannels = GetNumChannels(AudioSettings.speakerMode);
  57. }
  58. if (_debugLogging)
  59. {
  60. Debug.Log(string.Format("[UnityAudioCapture] SampleRate: {0}hz SpeakerMode: {1} BestDriverMode: {2} (DSP using {3} buffers of {4} bytes using {5} channels)", AudioSettings.outputSampleRate, AudioSettings.speakerMode.ToString(), AudioSettings.driverCaps.ToString(), numBuffers, bufferLength, _numChannels));
  61. }
  62. #endif
  63. _buffer = new float[bufferLength * _numChannels * numBuffers * BufferSize];
  64. _readBuffer = new float[bufferLength * _numChannels * numBuffers * BufferSize];
  65. _bufferIndex = 0;
  66. _bufferHandle = GCHandle.Alloc(_readBuffer, GCHandleType.Pinned);
  67. _overflowCount = 0;
  68. }
  69. void OnDisable()
  70. {
  71. lock (_lockObject)
  72. {
  73. _bufferIndex = 0;
  74. if (_bufferHandle.IsAllocated)
  75. _bufferHandle.Free();
  76. _readBuffer = _buffer = null;
  77. }
  78. _numChannels = 0;
  79. }
  80. public System.IntPtr ReadData(out int length)
  81. {
  82. lock (_lockObject)
  83. {
  84. System.Array.Copy(_buffer, 0, _readBuffer, 0, _bufferIndex);
  85. length = _bufferIndex;
  86. _bufferIndex = 0;
  87. }
  88. return _bufferHandle.AddrOfPinnedObject();
  89. }
  90. public void FlushBuffer()
  91. {
  92. lock (_lockObject)
  93. {
  94. _bufferIndex = 0;
  95. _overflowCount = 0;
  96. }
  97. }
  98. void OnAudioFilterRead(float[] data, int channels)
  99. {
  100. if (_buffer != null)
  101. {
  102. // TODO: use double buffering
  103. lock (_lockObject)
  104. {
  105. int length = Mathf.Min(data.Length, _buffer.Length - _bufferIndex);
  106. //System.Array.Copy(data, 0, _buffer, _bufferIndex, length);
  107. for (int i = 0; i < length; i++)
  108. {
  109. _buffer[i + _bufferIndex] = data[i];
  110. }
  111. _bufferIndex += length;
  112. if (length < data.Length)
  113. {
  114. _overflowCount++;
  115. Debug.LogWarning("[AVProMovieCapture] Audio buffer overflow, may cause sync issues. Disable this component if not recording Unity audio.");
  116. }
  117. }
  118. }
  119. }
  120. static public int GetNumChannels(AudioSpeakerMode mode)
  121. {
  122. int result = 0;
  123. switch (mode)
  124. {
  125. //case AudioSpeakerMode.Raw:
  126. // break;
  127. case AudioSpeakerMode.Mono:
  128. result = 1;
  129. break;
  130. case AudioSpeakerMode.Stereo:
  131. result = 2;
  132. break;
  133. case AudioSpeakerMode.Quad:
  134. result = 4;
  135. break;
  136. case AudioSpeakerMode.Surround:
  137. result = 5;
  138. break;
  139. case AudioSpeakerMode.Mode5point1:
  140. result = 6;
  141. break;
  142. case AudioSpeakerMode.Mode7point1:
  143. result = 8;
  144. break;
  145. case AudioSpeakerMode.Prologic:
  146. result = 2;
  147. break;
  148. }
  149. return result;
  150. }
  151. }
  152. }