Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

check current Microphone input volume

Discussion in 'Scripting' started by dergerntod, Apr 24, 2012.

  1. dergerntod

    dergerntod

    Joined:
    Apr 24, 2012
    Posts:
    3
    hi there!

    i'm trying to use the player's voice to control ingame objects directly (without any delay). i have to check how loud the user shouts into his/her microphone. currently it looks like this:

    Code (csharp):
    1.  
    2. //Script MicrophoneInput
    3. void Start(){
    4. if (device == null) device = Microphone.devices[0];
    5. audio.clip = Microphone.Start(MicrophoneInput.device, true, 999, 44100);
    6. while (!(Microphone.GetPosition(device) > 0))
    7. {} audio.Play();
    8. }
    9. void Update(){
    10.  
    11.         if (!active) return;
    12.         float[] data = new float[735];
    13.         audio.GetOutputData(data, 0);
    14. //take the median of the recorded samples
    15.         ArrayList s = new ArrayList();
    16.         foreach (float f in data)
    17.         {
    18.             s.Add(Mathf.Abs(f));
    19.         }
    20.         s.Sort();
    21.         Volume = (float)s[735 / 2];
    22. }
    23.  
    this works so far, but only if the audiosource of the object isn't muted. the problem is, i don't want the player to hear her-/himself

    i would appreciate any suggestions!
     
  2. wccrawford

    wccrawford

    Joined:
    Sep 30, 2011
    Posts:
    2,039
    Perhaps you could create an audio listener way outside the map and have it play on that one and determine the volume there, instead?

    There's probably a better way, but that would seem to work, if nothing else.
     
  3. dergerntod

    dergerntod

    Joined:
    Apr 24, 2012
    Posts:
    3
    ya that seems to work at first. problem is, that the audioclip created by the Microphone.Start-method is a 2D-Clip, so it doesn't matter where i play it, it's always the same volume
     
  4. bigmisterb

    bigmisterb

    Joined:
    Nov 6, 2010
    Posts:
    4,221
    I believe that the 3d aspect is in the audio source. I dont believe any clip is 3d initially, it is all in how you use it.
     
  5. dergerntod

    dergerntod

    Joined:
    Apr 24, 2012
    Posts:
    3
    well, as far as i know are audiosources capable of both, 2d and 3d sound. if i import some audioclips, i can choose if they are used 2d or 3d within the optionbox, but not via a script. at least i couldn't find the fitting methods. so i can't change that the clip that's produced by the Microphone-class is 2d, not 3d.
     
  6. crazyrems

    crazyrems

    Joined:
    Feb 25, 2013
    Posts:
    5
    It's been one year there is no activity on this thread, but Google brings me there.
    For the ones looking for a solution, I have one;

    Code (csharp):
    1. int dec = 128;
    2. float[] waveData = new float[dec];
    3. int micPosition = Microphone.GetPosition(null)-(dec+1); // null means the first microphone
    4. clipRecord.GetData(waveData, micPosition);
    5.  
    6. // Getting a peak on the last 128 samples
    7. float levelMax = 0;
    8. for (int i = 0; i < dec; i++) {
    9.     float wavePeak = waveData[i] * waveData[i];
    10.     if (levelMax < wavePeak) {
    11.         levelMax = wavePeak;
    12.     }
    13. }
    14. // levelMax equals to the highest normalized value power 2, a small number because < 1
    15. // use it like:
    16. UIGauge.level = Mathf.Sqrt(levelMax);
    17.  
    We just read the current recording audioclip, at the current recording position of the microphone
     
    ina, LegolasTai and KnightRiderGuy like this.
  7. Jean-Fabre

    Jean-Fabre

    Joined:
    Sep 6, 2007
    Posts:
    429
    Hi,

    @crazyrems

    just to step in cause I implement your code. You need to check that micposition is not a negative value else, GetData will fire "result == FMOD_OK" and it doesn't fire an exception so that error is fatal in all cases.

    so don't sample if micPosition<0


    bye,

    Jean
     
  8. atomtwist

    atomtwist

    Joined:
    Mar 20, 2013
    Posts:
    32
    Here is a complete script implementing the solution from above,
    as well as making sure that the app doesn't crash when it gets focused/unfocused on a mobile device, or the next level gets loaded.

    To access the Value from anywhere just do:
    Code (CSharp):
    1. MicInput.MicLoudness;
    Code (CSharp):
    1. public class MicInput : MonoBehaviour {
    2.      
    3.         public static float MicLoudness;
    4.  
    5.         private string _device;
    6.      
    7.         //mic initialization
    8.         void InitMic(){
    9.             if(_device == null) _device = Microphone.devices[0];
    10.             _clipRecord = Microphone.Start(_device, true, 999, 44100);
    11.         }
    12.      
    13.         void StopMicrophone()
    14.         {
    15.             Microphone.End(_device);
    16.         }
    17.      
    18.  
    19.         AudioClip _clipRecord = new AudioClip();
    20.         int _sampleWindow = 128;
    21.      
    22.         //get data from microphone into audioclip
    23.         float  LevelMax()
    24.         {
    25.             float levelMax = 0;
    26.             float[] waveData = new float[_sampleWindow];
    27.             int micPosition = Microphone.GetPosition(null)-(_sampleWindow+1); // null means the first microphone
    28.             if (micPosition < 0) return 0;
    29.             _clipRecord.GetData(waveData, micPosition);
    30.             // Getting a peak on the last 128 samples
    31.             for (int i = 0; i < _sampleWindow; i++) {
    32.                 float wavePeak = waveData[i] * waveData[i];
    33.                 if (levelMax < wavePeak) {
    34.                     levelMax = wavePeak;
    35.                 }
    36.             }
    37.             return levelMax;
    38.         }
    39.      
    40.      
    41.      
    42.         void Update()
    43.         {
    44.             // levelMax equals to the highest normalized value power 2, a small number because < 1
    45.             // pass the value to a static var so we can access it from anywhere
    46.             MicLoudness = LevelMax ();
    47.         }
    48.      
    49.         bool _isInitialized;
    50.         // start mic when scene starts
    51.         void OnEnable()
    52.         {
    53.             InitMic();
    54.             _isInitialized=true;
    55.         }
    56.      
    57.         //stop mic when loading a new level or quit application
    58.         void OnDisable()
    59.         {
    60.             StopMicrophone();
    61.         }
    62.      
    63.         void OnDestroy()
    64.         {
    65.             StopMicrophone();
    66.         }
    67.      
    68.      
    69.         // make sure the mic gets started & stopped when application gets focused
    70.         void OnApplicationFocus(bool focus) {
    71.             if (focus)
    72.             {
    73.                 //Debug.Log("Focus");
    74.              
    75.                 if(!_isInitialized){
    76.                     //Debug.Log("Init Mic");
    77.                     InitMic();
    78.                     _isInitialized=true;
    79.                 }
    80.             }      
    81.             if (!focus)
    82.             {
    83.                 //Debug.Log("Pause");
    84.                 StopMicrophone();
    85.                 //Debug.Log("Stop Mic");
    86.                 _isInitialized=false;
    87.              
    88.             }
    89.         }
    90.     }
    91.  
     
  9. I3lue

    I3lue

    Joined:
    Jan 16, 2016
    Posts:
    6
    Thank you man! This is one of the simplest and working scripts for Mic input out there!
     
    atomtwist likes this.
  10. Shulin_S

    Shulin_S

    Joined:
    Sep 30, 2016
    Posts:
    2
    Thanks to your answer. If I want to display the realtime volume in decibel, how to calculate by "wavedata". I mean I can not understand these numbers of MicLoudness.

    ---------------------------------------------------------------------------------------------------

    I have made it now! Thanks!
     
    Last edited: Sep 30, 2016
    Ikaro88 likes this.
  11. Ikaro88

    Ikaro88

    Joined:
    Jun 6, 2016
    Posts:
    296
    how you have solved it?
     
  12. zukinet

    zukinet

    Joined:
    Oct 30, 2016
    Posts:
    51
    Hi, i have try your script but it seems that the MicLoudNess no different between silent and noisy...

    or any idea to convert to desible unit ?

    any idea ?[/QUOTE]
     
    Last edited: Aug 15, 2017
  13. Cclark31

    Cclark31

    Joined:
    Feb 7, 2018
    Posts:
    5
    Hi!
    I've been using this script and it works great. Does anyone know how to adjust the microphone sensitivity? Not sure how it works.

    Thanks!
     
  14. A_munim

    A_munim

    Joined:
    Mar 11, 2017
    Posts:
    5
    Info/Explaination

    Hi!

    Okay, now to end this threat once and for all. READ CLOSELY(for people like me)

    The values MicLoudness returns, is a float linear to get it in decibels you need to do this

    Code (CSharp):
    1. float db = 20 * Mathf.Log10(Mathf.Abs(MicInput.MicLoudness));
    And there you have it Your volume in decibels

    If you want to get decibels or float linear of a recorded/audio clip

    First do not init the mic and in one of your scripts in start method call MicInput.StopMicrophone

    Then use the same code but just change the _cliprecord with your audio clip and instead of 128 use the length of the samples i.e

    Code (CSharp):
    1. AudioClip clip = myRecordedOrOwnClip;
    2.  
    3. _sampleWindow = clip.samples;
    If you have any problems let me know

    Full Script

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class MicInput : MonoBehaviour
    6. {
    7.     #region SingleTon
    8.  
    9.     public static MicInput Inctance { set; get; }
    10.  
    11.     #endregion
    12.  
    13.     public static float MicLoudness;
    14.     public static float MicLoudnessinDecibels;
    15.  
    16.     private string _device;
    17.  
    18.     //mic initialization
    19.     public void InitMic()
    20.     {
    21.         if (_device == null)
    22.         {
    23.             _device = Microphone.devices[0];
    24.         }
    25.         _clipRecord = Microphone.Start(_device, true, 999, 44100);
    26.         _isInitialized = true;
    27.     }
    28.  
    29.     public void StopMicrophone()
    30.     {
    31.         Microphone.End(_device);
    32.         _isInitialized = false;
    33.     }
    34.  
    35.  
    36.     AudioClip _clipRecord = new AudioClip();
    37.     AudioClip _recordedClip = new AudioClip();
    38.     int _sampleWindow = 128;
    39.  
    40.     //get data from microphone into audioclip
    41.     float MicrophoneLevelMax()
    42.     {
    43.         float levelMax = 0;
    44.         float[] waveData = new float[_sampleWindow];
    45.         int micPosition = Microphone.GetPosition(null) - (_sampleWindow + 1); // null means the first microphone
    46.         if (micPosition < 0) return 0;
    47.         _clipRecord.GetData(waveData, micPosition);
    48.         // Getting a peak on the last 128 samples
    49.         for (int i = 0; i < _sampleWindow; i++)
    50.         {
    51.             float wavePeak = waveData[i] * waveData[i];
    52.             if (levelMax < wavePeak)
    53.             {
    54.                 levelMax = wavePeak;
    55.             }
    56.         }
    57.         return levelMax;
    58.     }
    59.  
    60.     //get data from microphone into audioclip
    61.     float MicrophoneLevelMaxDecibels()
    62.     {
    63.  
    64.         float db = 20 * Mathf.Log10(Mathf.Abs(MicLoudness));
    65.  
    66.         return db;
    67.     }
    68.  
    69.     public float FloatLinearOfClip(AudioClip clip)
    70.     {
    71.         StopMicrophone();
    72.  
    73.         _recordedClip = clip;
    74.  
    75.         float levelMax = 0;
    76.         float[] waveData = new float[_recordedClip.samples];
    77.  
    78.         _recordedClip.GetData(waveData, 0);
    79.         // Getting a peak on the last 128 samples
    80.         for (int i = 0; i < _recordedClip.samples; i++)
    81.         {
    82.             float wavePeak = waveData[i] * waveData[i];
    83.             if (levelMax < wavePeak)
    84.             {
    85.                 levelMax = wavePeak;
    86.             }
    87.         }
    88.         return levelMax;
    89.     }
    90.  
    91.     public float DecibelsOfClip(AudioClip clip)
    92.     {
    93.         StopMicrophone();
    94.  
    95.         _recordedClip = clip;
    96.  
    97.         float levelMax = 0;
    98.         float[] waveData = new float[_recordedClip.samples];
    99.  
    100.         _recordedClip.GetData(waveData, 0);
    101.         // Getting a peak on the last 128 samples
    102.         for (int i = 0; i < _recordedClip.samples; i++)
    103.         {
    104.             float wavePeak = waveData[i] * waveData[i];
    105.             if (levelMax < wavePeak)
    106.             {
    107.                 levelMax = wavePeak;
    108.             }
    109.         }
    110.  
    111.         float db = 20 * Mathf.Log10(Mathf.Abs(levelMax));
    112.  
    113.         return db;
    114.     }
    115.  
    116.  
    117.  
    118.     void Update()
    119.     {
    120.         // levelMax equals to the highest normalized value power 2, a small number because < 1
    121.         // pass the value to a static var so we can access it from anywhere
    122.         MicLoudness = MicrophoneLevelMax();
    123.         MicLoudnessinDecibels = MicrophoneLevelMaxDecibels();
    124.     }
    125.  
    126.     bool _isInitialized;
    127.     // start mic when scene starts
    128.     void OnEnable()
    129.     {
    130.         InitMic();
    131.         _isInitialized = true;
    132.         Inctance = this;
    133.     }
    134.  
    135.     //stop mic when loading a new level or quit application
    136.     void OnDisable()
    137.     {
    138.         StopMicrophone();
    139.     }
    140.  
    141.     void OnDestroy()
    142.     {
    143.         StopMicrophone();
    144.     }
    145.  
    146.  
    147.     // make sure the mic gets started & stopped when application gets focused
    148.     void OnApplicationFocus(bool focus)
    149.     {
    150.         if (focus)
    151.         {
    152.             //Debug.Log("Focus");
    153.  
    154.             if (!_isInitialized)
    155.             {
    156.                 //Debug.Log("Init Mic");
    157.                 InitMic();
    158.             }
    159.         }
    160.         if (!focus)
    161.         {
    162.             //Debug.Log("Pause");
    163.             StopMicrophone();
    164.             //Debug.Log("Stop Mic");
    165.  
    166.         }
    167.     }
    168. }
    169.  
    170.  
    Thanks!
     
    Last edited: Apr 6, 2018
  15. kweiming

    kweiming

    Joined:
    Jun 18, 2017
    Posts:
    12
    After I updated to Unity 2018.1, I got such error:
    NullReferenceException: Object reference not set to an instance of an object
    MicInput.LevelMax () (at Assets/MicInput.cs:33)
    MicInput.Update () (at Assets/MicInput.cs:50)

    which line 33 is:
    Code (CSharp):
    1.         _clipRecord.GetData(waveData, micPosition);
    and line 50 is:
    Code (CSharp):
    1.         MicLoudness = LevelMax ();

    Does anyone knows how to fix it?
     
  16. Iman_col

    Iman_col

    Joined:
    Mar 24, 2018
    Posts:
    26
    error

    MicInput.cs(26,26): Error CS0143: El tipo 'UnityEngine.AudioClip' no tiene constructores definidos (CS0143) (Assembly-CSharp)
    MicInput.cs(28,28): Error CS0143: El tipo 'UnityEngine.AudioClip' no tiene constructores definidos (CS0143) (Assembly-CSharp)
     
  17. lilshaque

    lilshaque

    Joined:
    Oct 30, 2018
    Posts:
    1
    Here is the line 19 : AudioClip _clipRecord = new AudioClip();
    On line 19 it gives an error and says: "AudioClip " does not take a constructor that takes 0 arguments.

    How to fix it?


    Here is the line 19 : AudioClip _clipRecord = new AudioClip();
    On line 19 it gives an error and says: "AudioClip " does not take a constructor that takes 0 arguments.

    How to fix it?
     
  18. highlyinteractive

    highlyinteractive

    Joined:
    Sep 6, 2012
    Posts:
    116
    Just remove
    Code (CSharp):
    1. = new AudioClip()
    The microphone class is creating the audioclip anyway, so it's redundant.
     
  19. Liminal-Ridges

    Liminal-Ridges

    Joined:
    Oct 21, 2015
    Posts:
    255
    Hey guys, can i increase input decibels then output it?
     
  20. rahulpatil6220375

    rahulpatil6220375

    Joined:
    Dec 10, 2018
    Posts:
    19
     
  21. Mogge858

    Mogge858

    Joined:
    Jul 7, 2018
    Posts:
    1
    Hello! My output decibels are between -160db (quiet) to 0db (close to screaming). Does someone know why?
    (They should be posetive, right?)

    I copied the "full script" posted by A_munim with just one modification. I removed = new AudioClip(). To fix thoose errors as lilshaque mentioned.

    (Unity 2018.3.3f1)
     
    Serhii-Horun, Aleffeh and vovo801 like this.
  22. AmarIbr

    AmarIbr

    Joined:
    Sep 27, 2015
    Posts:
    8
    I'm getting a constant -infinty on my MicLoudnessinDecibels.

    I checked to make sure the mic was detected and it was.

    EDIT: okay so I didn't have an audio source lol, once I added that I was able to get some db data, however I'm having the same issue as Mogge858 where 0 is the highest number.

    ARG EDIT: Right so 0 db is unity gain. Data checks out. Anything above would mean that the data is being amplified. And I call myself an audio engineer...
     
    Last edited: Mar 24, 2019
  23. MrJamieMcC

    MrJamieMcC

    Joined:
    Nov 30, 2016
    Posts:
    2
    Hi guys. I'm really sorry to awake a dead post but i'm stuck. I've tried everything and i can't find the issue. I CAN'T get consistent results for my volume. Sometimes a whisper gives me a higher result than a shout and vice versa. Please can anybody help me?!


    Code (CSharp):
    1. private void Update()
    2.     {
    3.         micInputVolume = LevelMax();
    4.     }
    5.  
    6.  
    7.  
    8.     float LevelMax()
    9.     {
    10.         int _sampleWindow = 128;
    11.         float levelMax = 0;
    12.         float[] waveData = new float[_sampleWindow];
    13.         int micPosition = Microphone.GetPosition(null) - (_sampleWindow + 1); // null means the first microphone
    14.         if (micPosition < 0) return 0;
    15.         microphoneInput.GetData(waveData, micPosition);
    16.  
    17.         // Getting a peak on the last 128 samples
    18.         for (int i = 0; i < _sampleWindow; i++)
    19.         {
    20.             float wavePeak = waveData[i] * waveData[i];
    21.             if (levelMax < wavePeak)
    22.             {
    23.                 levelMax = wavePeak;
    24.             }
    25.         }
    26.         return levelMax;
    27.     }
     
  24. artofmining

    artofmining

    Joined:
    May 1, 2016
    Posts:
    83
    Is it possibly to do with the fact that in decibels a whisper can often be louder that a raised voice. Not sure it it's true but I read somewhere a babys scream is intended for high decibel range to get attention. Also a whisper can sometimes be louder than a seargent major whaling at his platoon. It might not carry RANGE but in decibels a whisper is greater. Correct me if this is wrong. Cheers
     
  25. artofmining

    artofmining

    Joined:
    May 1, 2016
    Posts:
    83
    Can someone kindly explain how to get the audio playback from this mic input script. I know there might be delay but that might be to my advantage as Im using the script to action lipsync on a character using blendshapes based on volume levels. Reason I want the audio playback is to change the pitch to a cartoon voice. The delay in playback will likely sync up with the small delay in mouth actions from the volume inputs. Many Thanks!
     
  26. nykwil

    nykwil

    Joined:
    Feb 28, 2015
    Posts:
    49
    Just stumbled in here, but loudness is a very complicated thing because it's time and delta based. I think what you want is to calculate the RMS of the audio then convert that to dbs. Specify a period (length)
    Code (CSharp):
    1.    public static float ComputeRMS( float[] buffer, int offset, ref int length )
    2.     {
    3.         // sum of squares
    4.         float sos = 0f;
    5.         float val;
    6.         if( offset + length > buffer.Length )
    7.         {
    8.             length = buffer.Length - offset;
    9.         }
    10.         for( int i = 0; i < length; i++ )
    11.         {
    12.             val = buffer[ offset ];
    13.             sos += val * val;
    14.             offset ++;
    15.         }
    16.         // return sqrt of average
    17.         return Mathf.Sqrt( sos / length );
    18.     }
    19.     public static float ComputeDB( float[] buffer, int offset, ref int length )
    20.     {
    21.         float rms;
    22.         rms = ComputeRMS( buffer, offset, ref length );
    23.         // could divide rms by reference power, simplified version here with ref power of 1f.
    24.         // will return negative values: 0db is the maximum.
    25.         return 10 * Mathf.Log10( rms );
    26.     }
     
    ROBYER1 likes this.
  27. dakomz

    dakomz

    Joined:
    Nov 12, 2019
    Posts:
    40
    in light of the example further up which has `_sampleWindow` - what would `offset` and `length` be here @nykwil ?
     
  28. nykwil

    nykwil

    Joined:
    Feb 28, 2015
    Posts:
    49
    The rms is calculated against a certain chunk of time. length is the number of samples and offset is the time into the buffer that it starts calculating it.
     
    dakomz likes this.
  29. awinder

    awinder

    Joined:
    Mar 12, 2018
    Posts:
    1
    I followed the same step as mentioned by @Mogge858, but was still getting a constant -infinity for MicLoudnessinDecibels. I also tried adding an audio source to the GameManager with the script as mentioned by @AmarBagh; however, the MicLoudnessinDecibels remained as -infinity. Does anyone know how to resolve this problem? For example, do I need to change anything in the code or tune the properties of audio source? Thanks!
     
    Visible_Sounds likes this.
  30. Visible_Sounds

    Visible_Sounds

    Joined:
    Feb 5, 2019
    Posts:
    2
    also having the same problem as awinder
     
  31. justinmvickers

    justinmvickers

    Joined:
    Mar 24, 2017
    Posts:
    1
  32. recr0

    recr0

    Joined:
    Aug 20, 2019
    Posts:
    4
    @awinder i am facing the same issue too if you have found out the solution can you share it
     
  33. recr0

    recr0

    Joined:
    Aug 20, 2019
    Posts:
    4
    i am facing a issue where my MicLoudnessinDecibels reamins - infinity
     
  34. JohannChristoph

    JohannChristoph

    Joined:
    Jun 21, 2009
    Posts:
    141
    yeah thanks guys! I'm almost there.
    @nykwil Yes the RMS would make a lot of sense. But I don't know how to call the two methods:
    ComputeRMS(...) and ComputeDB(...)
    and what to put into the first two arguments?
     
  35. JohannChristoph

    JohannChristoph

    Joined:
    Jun 21, 2009
    Posts:
    141
    To kind of RMS I helped myself with MathF.smoothdamp.
     
  36. ina

    ina

    Joined:
    Nov 15, 2010
    Posts:
    1,080
    I get this error from the microphone :( on the .GetData() line

    ./Modules/Audio/Public/sound/SoundManager.cpp(716) : Error executing result = instance->m_Sound->lock(offsetBytes, lengthBytes, &ptr1, &ptr2, &len1, &len2) (An invalid parameter was passed to this function. )
    UnityEngine.AudioClip:GetData (single[],int)