Advertisement
Guest User

AudioSourceFactory

a guest
Jun 4th, 2018
157
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 13.70 KB | None | 0 0
  1. public class AudioRecorder : MonoBehaviour, ExitGames.Client.Photon.Voice.IAudioReader<float>
  2. {
  3. /// <summary>
  4. /// Called when the recorder started listening. Analyzes audio for input.
  5. /// </summary>
  6. public Action RecorderDidStartListening;
  7.  
  8. /// <summary>
  9. /// Called when the recorder detects audio over the threshold.
  10. /// </summary>
  11. public Action RecorderDidStartMemorizing;
  12.  
  13. /// <summary>
  14. /// Called when the recorder memorized audio. Between Start memorizing and Stop memorizing.
  15. /// </summary>
  16. public Action<byte[]> RecorderDidPartialWithBytes;
  17.  
  18. /// <summary>
  19. /// Called when the recorder stopped. Both listening and memorizing stop.
  20. /// </summary>
  21. public Action RecorderDidStop;
  22.  
  23. /// <summary>
  24. /// Called when the rms of the audio updated.
  25. /// </summary>
  26. public Action<float> RMSUpdated;
  27.  
  28. [Header("Tweaks")]
  29. /// <summary>
  30. /// The record threshold.
  31. /// </summary>
  32. public bool useAutoCalibratedThresholdValue = true;
  33.  
  34. public double recordThresholdDecibels = -32;
  35.  
  36. public float minRMS = 0.002f;
  37. public float maxRMS = 0.9f;
  38.  
  39. /// <summary>
  40. /// The analyze seconds.
  41. /// </summary>
  42. public int analyzeSeconds = 15;
  43.  
  44. public float preThresholdSeconds = 0.5f;
  45.  
  46. public int preThresholdFrames
  47. {
  48. get { return (int) (this.preThresholdSeconds * 60); }
  49. }
  50.  
  51. /// <summary>
  52. /// The end recording delay seconds.
  53. /// </summary>
  54. public float endRecordingDelaySeconds = 2;
  55.  
  56. public float timeoutSeconds = 7;
  57.  
  58. [Header("Debug")]
  59. /// <summary>
  60. /// The debug. Default value false.
  61. /// </summary>
  62. public bool debug = false;
  63.  
  64. /// <summary>
  65. /// Is the recorder recording.
  66. /// </summary>
  67. [HideInInspector] public bool isRecording = false;
  68.  
  69. public bool isListening
  70. {
  71. get { return this.isMemorizing; }
  72. }
  73.  
  74. /// <summary>
  75. /// The input RMS.
  76. /// </summary>
  77. [HideInInspector] public float rms = 0;
  78.  
  79. [HideInInspector] public double decibels = 0;
  80.  
  81. private ArrayList recordDataToSend;
  82. private AudioClip alwaysRecordingAudioClip;
  83. private float secondsIndex = 0;
  84. private int preThresholdIndex = 0;
  85. private int lastSampleIndex = 0;
  86. private bool isOverRMS = false;
  87. private bool isFirstTime = false;
  88. private bool isMemorizing = false;
  89.  
  90. private Delay delayEndRecording = new Delay();
  91. private Delay timeoutDelay = new Delay();
  92.  
  93. private MemoryStream memstream;
  94. private MemoryStream preMemStream;
  95. private string[] connectedDevices;
  96.  
  97.  
  98. private int micPrevPos;
  99. private int micLoopCnt;
  100. private int readAbsPos;
  101.  
  102. public int SamplingRate
  103. {
  104. get { return this.alwaysRecordingAudioClip.frequency; }
  105. }
  106.  
  107. public int Channels
  108. {
  109. get { return this.alwaysRecordingAudioClip.channels; }
  110. }
  111.  
  112. private PhotonView _photonView;
  113.  
  114. #region LIFECYCLE
  115.  
  116. private void Start()
  117. {
  118. _photonView = GetComponent<PhotonView>();
  119.  
  120. if (_photonView != null && !_photonView.isMine)
  121. {
  122. Destroy(this);
  123. }
  124.  
  125. connectedDevices = Microphone.devices;
  126. if (this.useAutoCalibratedThresholdValue)
  127. {
  128. // MicrophoneCalibratorManager.Instance.CalibrationDidFinishWithSuccess.AddListener (() => {
  129. // float calibratedRMS = MicrophoneCalibratorManager.Instance.calibratedThreshold;
  130. //
  131. // this.recordThresholdDecibels = (float)(20 * Math.Log10 (calibratedRMS));
  132. // this.minRMS = calibratedRMS;
  133. // });
  134.  
  135. this.recordThresholdDecibels = MicrophoneCalibrationInfo.Instance.CalibratedDecibels;
  136. this.minRMS = MicrophoneCalibrationInfo.Instance.calibratedRMS;
  137. }
  138.  
  139. this.recordDataToSend = new ArrayList();
  140. this.secondsIndex = 0;
  141. this.lastSampleIndex = 0;
  142.  
  143. if (Microphone.devices.Length < 1)
  144. {
  145. return;
  146. }
  147.  
  148. var frequency = 8000;
  149. this.alwaysRecordingAudioClip = Microphone.Start(connectedDevices[0], true, 1, frequency);
  150. }
  151.  
  152. private void Update()
  153. {
  154. if (this.isRecording)
  155. {
  156. int micPosition = Microphone.GetPosition(null);
  157. int diff = micPosition - this.lastSampleIndex;
  158.  
  159. if (diff > 0)
  160. {
  161. this.rms = this.alwaysRecordingAudioClip.GetRMS(diff, this.lastSampleIndex);
  162. this.decibels = 20 * Math.Log10(rms);
  163.  
  164. if (this.RMSUpdated != null)
  165. {
  166. float rmsPercent = (rms - this.minRMS) / (this.maxRMS - this.minRMS);
  167.  
  168. this.RMSUpdated(rmsPercent);
  169. }
  170.  
  171. if (this.debug)
  172. {
  173. // MVRDebug.Log (this.GetDebugDescription () + "RMS: " + rms);
  174.  
  175. // MVRDebug.Log (this.GetDebugDescription () + "Decibels: " + this.decibels);
  176. }
  177. }
  178.  
  179. if (this.secondsIndex < this.analyzeSeconds)
  180. {
  181. this.secondsIndex += 1;
  182. }
  183. else
  184. {
  185. this.AnalyzeInput(micPosition, diff);
  186. this.secondsIndex = 0;
  187. }
  188.  
  189. if (this.preThresholdIndex < this.preThresholdFrames)
  190. {
  191. this.preThresholdIndex++;
  192. }
  193. else
  194. {
  195. this.preMemStream.Flush();
  196. this.preMemStream.SetLength(0);
  197. this.preThresholdIndex = 0;
  198. }
  199. }
  200. }
  201.  
  202. #endregion
  203.  
  204. #region PUBLIC
  205.  
  206. /// <summary>
  207. /// Starts the listening.
  208. /// </summary>
  209. public void StartListening()
  210. {
  211. this.recordThresholdDecibels = MicrophoneCalibrationInfo.Instance.CalibratedDecibels;
  212. this.minRMS = MicrophoneCalibrationInfo.Instance.calibratedRMS;
  213.  
  214.  
  215. // this.alwaysRecordingAudioClip = Microphone.Start(connectedDevices[0], true, 4, 16000);
  216. // this.alwaysRecordingAudioClip = VoiceScript.MicWrapperTest.Mic;
  217. if (this.debug)
  218. {
  219. // MVRDebug.Log (this.GetDebugDescription () + "Recording did start listening!");
  220. }
  221.  
  222. this.isFirstTime = true;
  223. this.isMemorizing = false;
  224. this.isRecording = true;
  225. this.lastSampleIndex = 0;
  226.  
  227. this.memstream = new MemoryStream();
  228. this.preMemStream = new MemoryStream();
  229.  
  230. if (this.RecorderDidStartListening != null)
  231. {
  232. this.RecorderDidStartListening();
  233. }
  234. }
  235.  
  236. /// <summary>
  237. /// Stop recording.
  238. /// </summary>
  239. public void Stop()
  240. {
  241. this.Cancel();
  242.  
  243. if (this.RecorderDidStop != null)
  244. {
  245. this.RecorderDidStop();
  246. }
  247. }
  248.  
  249. public void Cancel()
  250. {
  251. if (!this.isRecording)
  252. {
  253. return;
  254. }
  255.  
  256. if (this.delayEndRecording.IsWaiting)
  257. {
  258. this.delayEndRecording.Stop();
  259. }
  260.  
  261. if (this.timeoutDelay.IsWaiting)
  262. {
  263. this.timeoutDelay.Stop();
  264. }
  265.  
  266. // string[] connectedDevices = Microphone.devices;
  267. // Microphone.End(connectedDevices[0]);
  268. // this.alwaysRecordingAudioClip = null;
  269. this.memstream.Flush();
  270. this.memstream.Close();
  271.  
  272. this.preMemStream.Flush();
  273. this.preMemStream.Close();
  274.  
  275. this.recordDataToSend.Clear();
  276. this.isRecording = false;
  277. this.isFirstTime = false;
  278. this.isMemorizing = false;
  279.  
  280. if (this.debug)
  281. {
  282. // MVRDebug.Log (this.GetDebugDescription () + "Audio recorder cancelled!");
  283. }
  284. }
  285.  
  286. #endregion
  287.  
  288. #region PRIVATE
  289.  
  290. private void AnalyzeInput(int micPosition, int diff)
  291. {
  292. if (diff > 0)
  293. {
  294. //if rms > recordThreshold => user is speaking.
  295. if (this.decibels > this.recordThresholdDecibels)
  296. {
  297. //Trigger memoryze record
  298. this.isMemorizing = true;
  299. this.isOverRMS = true;
  300.  
  301. if (this.isFirstTime)
  302. {
  303. this.isFirstTime = false;
  304.  
  305. this.preMemStream.WriteTo(this.memstream);
  306.  
  307. if (this.debug)
  308. {
  309. // MVRDebug.Log (this.GetDebugDescription () + "User is speaking");
  310. }
  311.  
  312. if (this.RecorderDidStartMemorizing != null)
  313. {
  314. this.RecorderDidStartMemorizing();
  315. }
  316.  
  317. this.timeoutDelay.Wait(this.timeoutSeconds, () => { this.DelayedEndRecording(); });
  318. }
  319.  
  320. if (this.delayEndRecording.IsWaiting)
  321. {
  322. this.delayEndRecording.Stop();
  323. }
  324. }
  325. else if (this.isMemorizing && !this.delayEndRecording.IsWaiting)
  326. {
  327. this.delayEndRecording.Wait(this.endRecordingDelaySeconds, this.DelayedEndRecording);
  328.  
  329. if (this.RecorderDidPartialWithBytes != null)
  330. {
  331. byte[] audioData = this.memstream.GetBuffer();
  332.  
  333. this.RecorderDidPartialWithBytes(audioData);
  334.  
  335. this.memstream.Flush();
  336. this.memstream.SetLength(0);
  337. }
  338.  
  339. this.recordDataToSend.Clear();
  340. }
  341.  
  342. float[] chunkedAudio = this.alwaysRecordingAudioClip.GetSamples(diff, this.lastSampleIndex);
  343. AudioClip ceva = AudioClip.Create("yolo", chunkedAudio.Length, 1, 8000, false);
  344. ceva.SetData(chunkedAudio, 0);
  345.  
  346. byte[] data = ceva.ToBytes();
  347.  
  348. if (this.isFirstTime)
  349. {
  350. this.preMemStream.Flush();
  351. this.preMemStream.Write(data, 0, data.Length);
  352. }
  353.  
  354. if (this.isOverRMS || this.isMemorizing)
  355. {
  356. this.memstream.Write(data, 0, data.Length);
  357. }
  358. }
  359.  
  360. this.lastSampleIndex = micPosition;
  361. }
  362.  
  363. private void DelayedEndRecording()
  364. {
  365. if (this.timeoutDelay.IsWaiting)
  366. {
  367. this.timeoutDelay.Stop();
  368. }
  369.  
  370. this.isOverRMS = false;
  371. this.isMemorizing = false;
  372. this.isRecording = false;
  373.  
  374. if (this.debug)
  375. {
  376. // MVRDebug.Log (this.GetDebugDescription () + "User finished speaking!");
  377. }
  378.  
  379. // string[] connectedDevices = Microphone.devices;
  380. // Microphone.End(connectedDevices[0]);
  381.  
  382.  
  383. this.recordDataToSend.Clear();
  384. this.memstream.Flush();
  385. this.memstream.Close();
  386. // this.alwaysRecordingAudioClip = null;
  387.  
  388. if (this.RecorderDidPartialWithBytes != null)
  389. {
  390. this.RecorderDidPartialWithBytes(null);
  391. }
  392.  
  393. if (this.RecorderDidStop != null)
  394. {
  395. this.RecorderDidStop();
  396. }
  397. }
  398.  
  399. #endregion
  400.  
  401.  
  402. #region VOIP
  403.  
  404. /// <summary>
  405. /// Called every frame by Photon Voice Recorder.
  406. /// Sends microphone input over IP.
  407. /// Returns true if there is enough data to send, false otherwise.
  408. /// The part of the buffer that isnt sent this frame will be preserved and sent in the next frame.
  409. /// </summary>
  410. public bool Read(float[] buffer)
  411. {
  412. int micPos = Microphone.GetPosition(null);
  413. // loop detection
  414. if (micPos < micPrevPos)
  415. {
  416. micLoopCnt++;
  417. }
  418.  
  419. micPrevPos = micPos;
  420.  
  421. var micAbsPos = micLoopCnt * this.alwaysRecordingAudioClip.samples + micPos;
  422.  
  423. var bufferSamplesCount = buffer.Length / alwaysRecordingAudioClip.channels;
  424.  
  425. var nextReadPos = this.readAbsPos + bufferSamplesCount;
  426. if (nextReadPos < micAbsPos)
  427. {
  428. this.alwaysRecordingAudioClip.GetData(buffer, this.readAbsPos % this.alwaysRecordingAudioClip.samples);
  429. this.readAbsPos = nextReadPos;
  430. return true;
  431. }
  432. else
  433. {
  434. return false;
  435. }
  436. }
  437.  
  438. public void Dispose()
  439. {
  440. Microphone.End(connectedDevices[0]);
  441. }
  442.  
  443. #endregion
  444. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement