Newer
Older
HoloAnatomy / Assets / HoloToolkit-Examples / Input / Scripts / MicStreamDemo.cs
SURFACEBOOK2\jackwynne on 25 May 2018 5 KB v1
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See LICENSE in the project root for license information.

using UnityEngine;

namespace HoloToolkit.Unity.InputModule.Tests
{
    [RequireComponent(typeof(AudioSource))]
    public class MicStreamDemo : MonoBehaviour
    {
        /// <summary>
        /// Which type of microphone/quality to access.
        /// </summary>
        public MicStream.StreamCategory StreamType = MicStream.StreamCategory.HIGH_QUALITY_VOICE;

        /// <summary>
        /// Can boost volume here as desired. 1 is default.
        /// <remarks>Can be updated at runtime.</remarks> 
        /// </summary>
        public float InputGain = 1;

        /// <summary>
        /// if keepAllData==false, you'll always get the newest data no matter how long the program hangs for any reason,
        /// but will lose some data if the program does hang.
        /// <remarks>Can only be set on initialization.</remarks>
        /// </summary>
        public bool KeepAllData;

        /// <summary>
        /// If true, Starts the mic stream automatically when this component is enabled.
        /// </summary>
        public bool AutomaticallyStartStream = true;

        /// <summary>
        /// Plays back the microphone audio source though default audio device.
        /// </summary>
        public bool PlaybackMicrophoneAudioSource = true;

        /// <summary>
        /// The name of the file to which to save audio (for commands that save to a file).
        /// </summary>
        public string SaveFileName = "MicrophoneTest.wav";

        /// <summary>
        /// Records estimation of volume from the microphone to affect other elements of the game object.
        /// </summary>
        private float averageAmplitude;

        /// <summary>
        /// Minimum size the demo cube can be during runtime.
        /// </summary>
        [SerializeField]
        private float minObjectScale = .3f;

        private bool isRunning;

        public bool IsRunning
        {
            get { return isRunning; }
            private set
            {
                isRunning = value;
                CheckForErrorOnCall(isRunning ? MicStream.MicPause() : MicStream.MicResume());
            }
        }

        #region Unity Methods

        private void OnAudioFilterRead(float[] buffer, int numChannels)
        {
            // this is where we call into the DLL and let it fill our audio buffer for us
            CheckForErrorOnCall(MicStream.MicGetFrame(buffer, buffer.Length, numChannels));

            float sumOfValues = 0;

            // figure out the average amplitude from this new data
            for (int i = 0; i < buffer.Length; i++)
            {
                if (float.IsNaN(buffer[i]))
                {
                    buffer[i] = 0;
                }

                buffer[i] = Mathf.Clamp(buffer[i], -1f, 1f);
                sumOfValues += Mathf.Clamp01(Mathf.Abs(buffer[i]));
            }
            averageAmplitude = sumOfValues / buffer.Length;
        }

        private void OnEnable()
        {
            IsRunning = true;
        }

        private void Awake()
        {
            CheckForErrorOnCall(MicStream.MicInitializeCustomRate((int)StreamType, AudioSettings.outputSampleRate));
            CheckForErrorOnCall(MicStream.MicSetGain(InputGain));

            if (!PlaybackMicrophoneAudioSource)
            {
                gameObject.GetComponent<AudioSource>().volume = 0; // can set to zero to mute mic monitoring
            }

            if (AutomaticallyStartStream)
            {
                CheckForErrorOnCall(MicStream.MicStartStream(KeepAllData, false));
            }

            print("MicStream selector demo");
            print("press Q to start stream to audio source, W will stop that stream");
            print("press A to start a recording and S to stop that recording and save it to a wav file.");
            print("Since this all goes through the AudioSource, you can mute the mic while using it there, or do anything else you would do with an AudioSource");
            print("In this demo, we start the stream automatically, and then change the size of the GameObject based on microphone signal amplitude");
            isRunning = true;
        }

        private void Update()
        {
            CheckForErrorOnCall(MicStream.MicSetGain(InputGain));

            if (Input.GetKeyDown(KeyCode.Q))
            {
                CheckForErrorOnCall(MicStream.MicStartStream(KeepAllData, false));
            }
            else if (Input.GetKeyDown(KeyCode.W))
            {
                CheckForErrorOnCall(MicStream.MicStopStream());
            }
            else if (Input.GetKeyDown(KeyCode.A))
            {
                CheckForErrorOnCall(MicStream.MicStartRecording(SaveFileName, false));
            }
            else if (Input.GetKeyDown(KeyCode.S))
            {
                string outputPath = MicStream.MicStopRecording();
                Debug.Log("Saved microphone audio to " + outputPath);
                CheckForErrorOnCall(MicStream.MicStopStream());
            }

            gameObject.transform.localScale = new Vector3(minObjectScale + averageAmplitude, minObjectScale + averageAmplitude, minObjectScale + averageAmplitude);
        }

        private void OnApplicationPause(bool pause)
        {
            IsRunning = !pause;
        }

        private void OnDisable()
        {
            IsRunning = false;
        }

        private void OnDestroy()
        {
            CheckForErrorOnCall(MicStream.MicDestroy());
        }

#if !UNITY_EDITOR
        private void OnApplicationFocus(bool focused)
        {
            IsRunning = focused;
        }
#endif
        #endregion

        private static void CheckForErrorOnCall(int returnCode)
        {
            MicStream.CheckForErrorOnCall(returnCode);
        }

        public void Enable()
        {
            IsRunning = true;
        }

        public void Disable()
        {
            IsRunning = false;
        }
    }
}