Search Unity

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:
    300
    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:
    27
    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:
    256
    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,084
    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)