Skip to content

Instantly share code, notes, and snippets.

@r618
Created October 21, 2017 12:01

Revisions

  1. r618 renamed this gist Oct 21, 2017. 1 changed file with 0 additions and 0 deletions.
    File renamed without changes.
  2. r618 created this gist Oct 21, 2017.
    192 changes: 192 additions & 0 deletions AudioInputLasp
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,192 @@
    /*
    * just example of tighter LASP <-> Unity exchange
    */

    using System.Collections;
    using UnityEngine;
    using UnityEngine.Events;

    [RequireComponent(typeof(AudioSource))]
    public class AudioInputLasp : MonoBehaviour
    {
    // ========================================================================================================================================
    #region Editor
    /// <summary>
    /// Recording samplerate provided by LASP default recording device
    /// </summary>
    [HideInInspector]
    int recRate = 0;

    [Header("[Setup]")]
    [Tooltip("When checked the recording will start automatically on Start with parameters set in Inspector. Otherwise StartCoroutine(Record()) of this component.")]
    public bool recordOnStart = true;

    #region Unity events
    [System.Serializable]
    public class EventWithStringParameter : UnityEvent<string> { };
    [System.Serializable]
    public class EventWithStringBoolParameter : UnityEvent<string, bool> { };
    [System.Serializable]
    public class EventWithStringStringParameter : UnityEvent<string, string> { };
    [System.Serializable]
    public class EventWithStringStringStringParameter : UnityEvent<string, string, string> { };

    [Header("[Events]")]
    public EventWithStringParameter OnRecordingStarted;
    public EventWithStringBoolParameter OnRecordingPaused;
    public EventWithStringParameter OnRecordingStopped;
    public EventWithStringStringParameter OnError;
    #endregion
    #endregion

    // ========================================================================================================================================
    #region Init
    /// <summary>
    /// Component startup sync
    /// Also in case of recording FMOD needs some time to enumerate all present recording devices - we need to wait for it. Check this flag when using from scripting.
    /// </summary>
    [HideInInspector]
    public bool ready = false;

    void Start()
    {
    // setup the AudioSource
    var audiosrc = this.GetComponent<AudioSource>();
    if (audiosrc)
    {
    audiosrc.playOnAwake = false;
    audiosrc.Stop();
    audiosrc.clip = null;
    }

    /*
    * Nudge LASP a little to open at start
    */
    float[] ftemp = new float[512];
    Lasp.AudioInput.RetrieveWaveform(Lasp.FilterType.Bypass, ftemp, Time.frameCount);

    if (this.recordOnStart)
    StartCoroutine(this.Record());

    this.ready = true;
    }

    #endregion

    // ========================================================================================================================================
    #region Recording
    [Header("[Runtime]")]
    [Tooltip("Set during recording.")]
    public bool isRecording = false;
    [Tooltip("Set during recording.")]
    public bool isPaused = false;

    public IEnumerator Record()
    {
    if (this.isRecording)
    {
    Debug.LogWarning("Already recording.");
    yield break;
    }

    if (!this.isActiveAndEnabled)
    {
    Debug.LogWarning("Will not start on disabled GameObject.");
    yield break;
    }

    this.isRecording = false;
    this.isPaused = false;

    this.Stop_Internal(); // try to clean partially started recording / Start initialized system

    /*
    * create some sound with corresponding rate
    */
    recRate = (int)Lasp.AudioInput.GetSampleRate();
    // LASP supports only mono
    var recChannels = 1;

    var outputChannles = 2; // note: this should be according to user selected output in AudioSettings.speakerMode

    var asource = this.GetComponent<AudioSource>();
    asource.pitch = (float)(recRate * recChannels) / (float)(AudioSettings.outputSampleRate * outputChannles);
    asource.Play();

    this.isRecording = true;

    if (this.OnRecordingStarted != null)
    this.OnRecordingStarted.Invoke(this.gameObject.name);

    yield return StartCoroutine(this.RecordCR());
    }

    int frameCountX;
    IEnumerator RecordCR()
    {
    while (this.isRecording)
    {
    this.frameCountX = Time.frameCount;
    yield return null;
    }
    }

    public void Pause(bool pause)
    {
    if (!this.isRecording)
    {
    Debug.LogWarning("Not recording..");
    return;
    }

    this.isPaused = pause;

    Debug.LogFormat("{0}", this.isPaused ? "paused." : "resumed.");

    if (this.OnRecordingPaused != null)
    this.OnRecordingPaused.Invoke(this.gameObject.name, this.isPaused);
    }

    void OnAudioFilterRead(float[] data, int channels)
    {
    Lasp.AudioInput.RetrieveWaveform(Lasp.FilterType.Bypass, data, this.frameCountX);
    }
    #endregion

    // ========================================================================================================================================
    #region Shutdown
    public void Stop()
    {
    Debug.Log("Stopping..");

    this.StopAllCoroutines();

    this.Stop_Internal();

    if (this.OnRecordingStopped != null)
    this.OnRecordingStopped.Invoke(this.gameObject.name);
    }

    /// <summary>
    /// Stop and try to release FMOD sound resources
    /// </summary>
    void Stop_Internal()
    {
    var asource = this.GetComponent<AudioSource>();
    if (asource)
    {
    asource.Stop();
    Destroy(asource.clip);
    asource.clip = null;
    }

    this.isRecording = false;
    this.isPaused = false;
    }

    void OnDisable()
    {
    this.Stop();
    }
    #endregion
    }