Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 12 Next capture
2021 2022 2023
1 capture
12 Jun 22 - 12 Jun 22
sparklines
Close Help
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
1
Question by Pelican_7 · Jan 25, 2019 at 03:00 PM · audioaudiosourcefmod

How can I control an AudioSource from the audio thread?

Hi. I am looking for a way to call audioSource.Play() from the audio thread, specifically from inside an OnAudioFilterRead callback. Currently, attempting to do so (understandably) causes an error stating that these methods must be called from the main thread.


Overview

I have a game that implements an audio step sequencer in OnAudioFilterRead. As you may know, to receive OnAudioFilterRead callbacks, the script must be attached to a game object with a playing AudioSource component.

The player can create many of these step sequencers and chain them together, causing one sequencer to play after another. When one sequencer completes its playback, I wish to begin playback of the next sequencer in the chain. All sequencers share the same metronome object, which can be queried each audio frame using the DSP time to retrieve the beats in the current audio buffer. This means that as long as I can ensure the OnAudioFilterRead callback of the next sequencer is rendering (i.e. its audio source is playing), it will pick up the next metronome beat in perfect beat-sync.

As such, the command to begin playback of the next sequencer is (audio) time critical – it must arrive before the next metronome beat (and ideally the same/next audio frame) in order to maintain beat-sync. It is for this reason that I would like to begin playback of the audio source with audioSource.Play() from the audio thread.

As an aside, I have tried picking up the command to play the next sequencer in the next Update cycle, and thus moving it to the main thread, however this is unreliable as to maintaining beat synchronisation. The command will sometimes arrive too late (the metronome's next beat has already occurred on the audio thread) and the sequencer will slip by one beat at the changeover point.


Current Solution

My current solution is to have all audio sources always playing and to control playback of the audio step sequencer script with its own IsPlaying flag. This removes the need to play/stop audio sources and I can control my sequencer playback from the audio thread easily by setting the flag. This works well for maintaining beat-synchronisation as the step sequencer's flag is set immediately and is guaranteed to be rendering on the next audio frame.

However, where this solution fails is that Unity (or FMOD) imposes a limit of 255 audio sources playing at once (the maximum number or real voices). The player can create long chains with potentially hundreds of sequencers and therefore hundreds of audio sources. By leaving audio sources playing and controlling playback with my own flag, I hit this limitation when the player creates more than 255 sequencers (even if none are actually playing via the IsPlaying flag). The 256th+ audio sources will not be played by the engine, and thus the OnAudioFilterRead callbacks will not be invoked. (To be clear, I'm not playing 255 sounds at once - I only have them 'playing' to ensure their OnAudioFilterRead callback is invoked.)


Desired Solution

I would like to be able to toggle each audio source's playback from the audio thread. This would allow me to have hundreds of audio sources present in the scene as outlined above, and toggle their playback whilst maintaining beat synchronisation. Is there a way I can do this?


Thanks in advance. -andy.

P.S. This is a link to my game running – it might help to illustrate the points made – https://www.youtube.com/watch?v=MpeOsIUgUoM. Each lily flower is an audio step sequencer, the lily pads are the mechanism by which players 'chain' sequencers together.

Comment
Add comment
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

1 Reply

· Add your reply
  • Sort: 
avatar image
0

Answer by Legend_Bacon · Jan 25, 2019 at 04:52 PM

Hello there,


And first, thank you for making your post so clear. It really helps.


Second, this is my go-to solution to "work around" the threading problem in Unity:

• Create a Script called "Dispatcher"

• Throw this code in it:


 using System.Collections;
 using System.Collections.Generic;
 using UnityEngine;
 using System;
 
 public class Dispatcher : MonoBehaviour 
 {
     public static Queue<Action> ExecuteOnMainThread = new Queue<Action>();
 
     public void Update()
     {
         while (ExecuteOnMainThread.Count > 0)
         {
             ExecuteOnMainThread.Dequeue().Invoke();
         }
     }
 
 }


• Throw that script on an object in the scene

• Now, anytime you have a line of code that says "can only be called from the main thread", execute it like this:


  DispatcherScript.ExecuteOnMainThread.Enqueue(() =>
 {
   //Put your code in here
   Debug.Log("This is a debug log called on the main thread!");
   Debug.Log("This is another debug log!");
 });


I use this to handle network events, or to know when an external EXE I've started has stopped running. So far it's always worked, but in your case I would check for potential delays.

I haven't played your video (at work atm), but if you're going for a perfect beat-sync even the slightest delay could be an issue.


I hope that helps!

Cheers,

~LegendBacon

Comment
Add comment · Show 1 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image Pelican_7 · Jan 26, 2019 at 10:24 AM 0
Share

Hi. Thanks so much for the response. A couple of points:

  1. We have to be careful allocating memory on the audio thread, which the Enqueue will do. Code executing on the audio thread should be deter$$anonymous$$istic/predicatable as to its running time, which memory allocation isn't. This is to avoid starving the DSP of audio samples and thus causing clicks/pops. (If you're interested this is a good post on the topic). Ins$$anonymous$$d I tried a solution that simply toggles a flag on the audio thread, which the Update loop checks for. Which leads me to:

  2. It is not guaranteed that the main thread will pick this up in time. This solution will sometimes work, and sometimes it will miss a beat. I believe it is because if the main thread gets busy for a frame or two for whatever reason, it can cause the Update to be invoked too late (after the next audio frame). On slower machines this can also become more pronounced. I'd like to be able to guarantee my audio source has begun playing by the next audio frame, which I'm not sure how I can do without directly calling it from the audio thread.

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this Question

Answers Answers and Comments

130 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

App crashes due to FMOD error 0 Answers

Question about audio (AudioSource). My ingame sound doesn't sound like the original audio file? 3 Answers

How can I play a sound effect many times without cutting the last sound effect? 1 Answer

Can't seem to play my AudioClip? 2 Answers

How to make menu which is able to list audio files, then load chosen one into the AudioSource in the scene 1 Answer


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges