Search Unity

  1. Unity 6 Preview is now available. To find out what's new, have a look at our Unity 6 Preview blog post.
    Dismiss Notice
  2. Unity is excited to announce that we will be collaborating with TheXPlace for a summer game jam from June 13 - June 19. Learn more.
    Dismiss Notice

Question How can one keep a continuously looping mic synchronized?

Discussion in 'Audio & Video' started by dynamicbutter, Apr 30, 2024.

  1. dynamicbutter

    dynamicbutter

    Joined:
    Jun 11, 2021
    Posts:
    70
    My app continuously processes the latest microphone data. It works for a while but eventually loses sync. I am looking for a way to either re-sync or never lose sync. Either option is fine. I have read a lot of posts here which have gotten me as far as I am. I haven't found anything that completely solves the problem but do apologize if this has already been answered.

    The app consists of an AudioListener (named Microphone below) which is assigned a continuous mic clip like this...
    Code (CSharp):
    1.  
    2. Microphone.Stop();
    3. Microphone.clip = UnityEngine.Microphone.Start(
    4.     micName,
    5.     true,
    6.     1,
    7.     AudioSettings.GetConfiguration().sampleRate);
    8. Microphone.Play();
    9. Microphone.timeSamples = 0;
    10.  
    The app implements OnAudioFilterRead which enqueues the data to be processed by the main thread (and the dsp time of the data) like this...
    Code (CSharp):
    1.  
    2. void OnAudioFilterRead(float[] data, int channels)
    3. {
    4.     // Copy interleaved Microphone channel data
    5.     for (var i = 0; i < data.Length; i += 2) {
    6.         // Use channel 0, discard channel 1
    7.         audioBuffer[i >> 1] = data[i];
    8.     }
    9.     audioBuffers.Enqueue((AudioSettings.dspTime, audioBuffer));
    10. }
    11.  
    The main thread processes these buffers and calls GetOutputData throwing away the results (to stay in sync) like this...
    Code (CSharp):
    1.  
    2. // Do some processing...
    3. AudioListener.GetOutputData(trashBuf, 0);
    4.  
    As a side note, it seems odd that I need to call GetOutputData since I already have the data. Is there a more direct way to keep the read/write pointers sync'd?

    This runs ok for a while but eventually it loses sync. I can see from examining the dsp time that occasionally some buffers are not delivered to OnAudioFilterRead. This problem is easy to repeat when I load scenes (the GameObject that does all this is set to DontDestroyOnLoad), and probably other times as well.

    I would like to be able to re-sync whenever I detect a buffer has been skipped. Can anyone explain the sequence to restart all this so that its back in sync?
     
  2. dynamicbutter

    dynamicbutter

    Joined:
    Jun 11, 2021
    Posts:
    70
    I guess I finally realized at the end of writing the original post that staying in sync was a fools errand and it would be better to be able to detect and recover from syncloss. Restarting the mic turns out to be a lot like starting it in the first place ;) This seems to be working now.

    Code (CSharp):
    1. public static void RestartMic()
    2. {
    3.     Microphone.Stop();
    4.     Microphone.clip = UnityEngine.Microphone.Start(
    5.         MicName,
    6.         true,
    7.         MIC_LOOP_TIME,
    8.         AudioSettings.GetConfiguration().sampleRate);
    9.     Microphone.Play();
    10.     Microphone.timeSamples = 0;
    11.     Debug.Log($"mic restarted");
    12. }
    13.  
     
    SeventhString likes this.