Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- public class AudioRecorder : MonoBehaviour, ExitGames.Client.Photon.Voice.IAudioReader<float>
- {
- /// <summary>
- /// Called when the recorder started listening. Analyzes audio for input.
- /// </summary>
- public Action RecorderDidStartListening;
- /// <summary>
- /// Called when the recorder detects audio over the threshold.
- /// </summary>
- public Action RecorderDidStartMemorizing;
- /// <summary>
- /// Called when the recorder memorized audio. Between Start memorizing and Stop memorizing.
- /// </summary>
- public Action<byte[]> RecorderDidPartialWithBytes;
- /// <summary>
- /// Called when the recorder stopped. Both listening and memorizing stop.
- /// </summary>
- public Action RecorderDidStop;
- /// <summary>
- /// Called when the rms of the audio updated.
- /// </summary>
- public Action<float> RMSUpdated;
- [Header("Tweaks")]
- /// <summary>
- /// The record threshold.
- /// </summary>
- public bool useAutoCalibratedThresholdValue = true;
- public double recordThresholdDecibels = -32;
- public float minRMS = 0.002f;
- public float maxRMS = 0.9f;
- /// <summary>
- /// The analyze seconds.
- /// </summary>
- public int analyzeSeconds = 15;
- public float preThresholdSeconds = 0.5f;
- public int preThresholdFrames
- {
- get { return (int) (this.preThresholdSeconds * 60); }
- }
- /// <summary>
- /// The end recording delay seconds.
- /// </summary>
- public float endRecordingDelaySeconds = 2;
- public float timeoutSeconds = 7;
- [Header("Debug")]
- /// <summary>
- /// The debug. Default value false.
- /// </summary>
- public bool debug = false;
- /// <summary>
- /// Is the recorder recording.
- /// </summary>
- [HideInInspector] public bool isRecording = false;
- public bool isListening
- {
- get { return this.isMemorizing; }
- }
- /// <summary>
- /// The input RMS.
- /// </summary>
- [HideInInspector] public float rms = 0;
- [HideInInspector] public double decibels = 0;
- private ArrayList recordDataToSend;
- private AudioClip alwaysRecordingAudioClip;
- private float secondsIndex = 0;
- private int preThresholdIndex = 0;
- private int lastSampleIndex = 0;
- private bool isOverRMS = false;
- private bool isFirstTime = false;
- private bool isMemorizing = false;
- private Delay delayEndRecording = new Delay();
- private Delay timeoutDelay = new Delay();
- private MemoryStream memstream;
- private MemoryStream preMemStream;
- private string[] connectedDevices;
- private int micPrevPos;
- private int micLoopCnt;
- private int readAbsPos;
- public int SamplingRate
- {
- get { return this.alwaysRecordingAudioClip.frequency; }
- }
- public int Channels
- {
- get { return this.alwaysRecordingAudioClip.channels; }
- }
- private PhotonView _photonView;
- #region LIFECYCLE
- private void Start()
- {
- _photonView = GetComponent<PhotonView>();
- if (_photonView != null && !_photonView.isMine)
- {
- Destroy(this);
- }
- connectedDevices = Microphone.devices;
- if (this.useAutoCalibratedThresholdValue)
- {
- // MicrophoneCalibratorManager.Instance.CalibrationDidFinishWithSuccess.AddListener (() => {
- // float calibratedRMS = MicrophoneCalibratorManager.Instance.calibratedThreshold;
- //
- // this.recordThresholdDecibels = (float)(20 * Math.Log10 (calibratedRMS));
- // this.minRMS = calibratedRMS;
- // });
- this.recordThresholdDecibels = MicrophoneCalibrationInfo.Instance.CalibratedDecibels;
- this.minRMS = MicrophoneCalibrationInfo.Instance.calibratedRMS;
- }
- this.recordDataToSend = new ArrayList();
- this.secondsIndex = 0;
- this.lastSampleIndex = 0;
- if (Microphone.devices.Length < 1)
- {
- return;
- }
- var frequency = 8000;
- this.alwaysRecordingAudioClip = Microphone.Start(connectedDevices[0], true, 1, frequency);
- }
- private void Update()
- {
- if (this.isRecording)
- {
- int micPosition = Microphone.GetPosition(null);
- int diff = micPosition - this.lastSampleIndex;
- if (diff > 0)
- {
- this.rms = this.alwaysRecordingAudioClip.GetRMS(diff, this.lastSampleIndex);
- this.decibels = 20 * Math.Log10(rms);
- if (this.RMSUpdated != null)
- {
- float rmsPercent = (rms - this.minRMS) / (this.maxRMS - this.minRMS);
- this.RMSUpdated(rmsPercent);
- }
- if (this.debug)
- {
- // MVRDebug.Log (this.GetDebugDescription () + "RMS: " + rms);
- // MVRDebug.Log (this.GetDebugDescription () + "Decibels: " + this.decibels);
- }
- }
- if (this.secondsIndex < this.analyzeSeconds)
- {
- this.secondsIndex += 1;
- }
- else
- {
- this.AnalyzeInput(micPosition, diff);
- this.secondsIndex = 0;
- }
- if (this.preThresholdIndex < this.preThresholdFrames)
- {
- this.preThresholdIndex++;
- }
- else
- {
- this.preMemStream.Flush();
- this.preMemStream.SetLength(0);
- this.preThresholdIndex = 0;
- }
- }
- }
- #endregion
- #region PUBLIC
- /// <summary>
- /// Starts the listening.
- /// </summary>
- public void StartListening()
- {
- this.recordThresholdDecibels = MicrophoneCalibrationInfo.Instance.CalibratedDecibels;
- this.minRMS = MicrophoneCalibrationInfo.Instance.calibratedRMS;
- // this.alwaysRecordingAudioClip = Microphone.Start(connectedDevices[0], true, 4, 16000);
- // this.alwaysRecordingAudioClip = VoiceScript.MicWrapperTest.Mic;
- if (this.debug)
- {
- // MVRDebug.Log (this.GetDebugDescription () + "Recording did start listening!");
- }
- this.isFirstTime = true;
- this.isMemorizing = false;
- this.isRecording = true;
- this.lastSampleIndex = 0;
- this.memstream = new MemoryStream();
- this.preMemStream = new MemoryStream();
- if (this.RecorderDidStartListening != null)
- {
- this.RecorderDidStartListening();
- }
- }
- /// <summary>
- /// Stop recording.
- /// </summary>
- public void Stop()
- {
- this.Cancel();
- if (this.RecorderDidStop != null)
- {
- this.RecorderDidStop();
- }
- }
- public void Cancel()
- {
- if (!this.isRecording)
- {
- return;
- }
- if (this.delayEndRecording.IsWaiting)
- {
- this.delayEndRecording.Stop();
- }
- if (this.timeoutDelay.IsWaiting)
- {
- this.timeoutDelay.Stop();
- }
- // string[] connectedDevices = Microphone.devices;
- // Microphone.End(connectedDevices[0]);
- // this.alwaysRecordingAudioClip = null;
- this.memstream.Flush();
- this.memstream.Close();
- this.preMemStream.Flush();
- this.preMemStream.Close();
- this.recordDataToSend.Clear();
- this.isRecording = false;
- this.isFirstTime = false;
- this.isMemorizing = false;
- if (this.debug)
- {
- // MVRDebug.Log (this.GetDebugDescription () + "Audio recorder cancelled!");
- }
- }
- #endregion
- #region PRIVATE
- private void AnalyzeInput(int micPosition, int diff)
- {
- if (diff > 0)
- {
- //if rms > recordThreshold => user is speaking.
- if (this.decibels > this.recordThresholdDecibels)
- {
- //Trigger memoryze record
- this.isMemorizing = true;
- this.isOverRMS = true;
- if (this.isFirstTime)
- {
- this.isFirstTime = false;
- this.preMemStream.WriteTo(this.memstream);
- if (this.debug)
- {
- // MVRDebug.Log (this.GetDebugDescription () + "User is speaking");
- }
- if (this.RecorderDidStartMemorizing != null)
- {
- this.RecorderDidStartMemorizing();
- }
- this.timeoutDelay.Wait(this.timeoutSeconds, () => { this.DelayedEndRecording(); });
- }
- if (this.delayEndRecording.IsWaiting)
- {
- this.delayEndRecording.Stop();
- }
- }
- else if (this.isMemorizing && !this.delayEndRecording.IsWaiting)
- {
- this.delayEndRecording.Wait(this.endRecordingDelaySeconds, this.DelayedEndRecording);
- if (this.RecorderDidPartialWithBytes != null)
- {
- byte[] audioData = this.memstream.GetBuffer();
- this.RecorderDidPartialWithBytes(audioData);
- this.memstream.Flush();
- this.memstream.SetLength(0);
- }
- this.recordDataToSend.Clear();
- }
- float[] chunkedAudio = this.alwaysRecordingAudioClip.GetSamples(diff, this.lastSampleIndex);
- AudioClip ceva = AudioClip.Create("yolo", chunkedAudio.Length, 1, 8000, false);
- ceva.SetData(chunkedAudio, 0);
- byte[] data = ceva.ToBytes();
- if (this.isFirstTime)
- {
- this.preMemStream.Flush();
- this.preMemStream.Write(data, 0, data.Length);
- }
- if (this.isOverRMS || this.isMemorizing)
- {
- this.memstream.Write(data, 0, data.Length);
- }
- }
- this.lastSampleIndex = micPosition;
- }
- private void DelayedEndRecording()
- {
- if (this.timeoutDelay.IsWaiting)
- {
- this.timeoutDelay.Stop();
- }
- this.isOverRMS = false;
- this.isMemorizing = false;
- this.isRecording = false;
- if (this.debug)
- {
- // MVRDebug.Log (this.GetDebugDescription () + "User finished speaking!");
- }
- // string[] connectedDevices = Microphone.devices;
- // Microphone.End(connectedDevices[0]);
- this.recordDataToSend.Clear();
- this.memstream.Flush();
- this.memstream.Close();
- // this.alwaysRecordingAudioClip = null;
- if (this.RecorderDidPartialWithBytes != null)
- {
- this.RecorderDidPartialWithBytes(null);
- }
- if (this.RecorderDidStop != null)
- {
- this.RecorderDidStop();
- }
- }
- #endregion
- #region VOIP
- /// <summary>
- /// Called every frame by Photon Voice Recorder.
- /// Sends microphone input over IP.
- /// Returns true if there is enough data to send, false otherwise.
- /// The part of the buffer that isnt sent this frame will be preserved and sent in the next frame.
- /// </summary>
- public bool Read(float[] buffer)
- {
- int micPos = Microphone.GetPosition(null);
- // loop detection
- if (micPos < micPrevPos)
- {
- micLoopCnt++;
- }
- micPrevPos = micPos;
- var micAbsPos = micLoopCnt * this.alwaysRecordingAudioClip.samples + micPos;
- var bufferSamplesCount = buffer.Length / alwaysRecordingAudioClip.channels;
- var nextReadPos = this.readAbsPos + bufferSamplesCount;
- if (nextReadPos < micAbsPos)
- {
- this.alwaysRecordingAudioClip.GetData(buffer, this.readAbsPos % this.alwaysRecordingAudioClip.samples);
- this.readAbsPos = nextReadPos;
- return true;
- }
- else
- {
- return false;
- }
- }
- public void Dispose()
- {
- Microphone.End(connectedDevices[0]);
- }
- #endregion
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement