Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 13 Next capture
2021 2022 2023
2 captures
13 Jun 22 - 14 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 gregzo · Jan 13, 2012 at 08:28 AM · audiosynchronizationoffsetsample

Play(offsetInSamples) acuracy - still cannot get it to work perfectly

Hi to all!

Hi to all! Tried posting this on the forum, and not getting any love... . I still have the following issue: I am trying to play an audioclip exactly at sample 0 of another looping one. This works fine in an empty scene, but not in my application. To try to narrow down the problem, I made the following test, which reveals (on my machine at least) that Play(offsetInSamples) will be inaccurate if there is as much as a Print in the same function... Details of my test are below, any help would be greatly appreciated!

The scene contains a camera, and 3 GameObjects with 1 AudioSource each : metronome, met2 and met3. They all have the same AudioClip, which is a .25s click (precisely 11025 samples at 44100 hz). All sources set to loop, metronome audio source to PlayOnAwake.

Metronome has the following script attached to it:

 var met2 : GameObject;
 var met3 : GameObject;
 
 private var offset : int;
 
 function Update(){
      if(Input.GetKeyDown("2")){
           offset = audio.clip.samples - audio.timeSamples;
           if(met2.audio.isPlaying == false){
                met2.audio.Play(offset);
                print("anything"); //The Culprit
           }
           else{
                met2.audio.Stop();
           }
      }
 
      if(Input.GetKeyDown("3")){
           offset = audio.clip.samples-audio.timeSamples;
           if(met3.audio.isPlaying == false){
                met3.audio.Play(offset);
           }
           else{
                met3.audio.Stop();
           }
      }
 }

When I hit 3, sync is perfect, but if I hit 2, the metronomes are out of sync at least 10% of the times, and once in a while seriously out of sync (50ms) a few times in a row. It seems printing a string is enough to trigger this inaccuracy...

I'm using Unity 3.5, Windows XP, audio settings to best latency, decompress on load, file is a wav (2d sound, but the same applies to 3d sounds).

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

5 Replies

· Add your reply
  • Sort: 
avatar image
2
Best Answer

Answer by gregzo · Jan 13, 2012 at 09:49 AM

Solved. To get perfect sync, all the audio components need to be set to AudioVelocityUpdateMode.Fixed. Then, the before playing the 2nd clip(the one to synchronize), yield WaitForFixedUpdate and calculate the offset in samples. I spent so much time going crazy with this, I'll gladly post detailed steps if asked. I'm now firing different sequencers (tested up to 8 simultaneously), in sync or out of sync, at different bpm's, of varying lengths. Relief!

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 se7en · Jan 02, 2013 at 05:26 PM 0
Share

There is no documentation on AudioVelocityUpdate$$anonymous$$ode.Fixed - I tried using it yesterday but cannot figure out how to use it. Advice?

avatar image
1

Answer by gregzo · Feb 21, 2012 at 04:22 PM

Hi and sorry for the wait!

As before, the following script is attached to a gameObject containing an AudioSource which loops a click.

The scene also contains met2, another similar object but without this script attached.

Pressing space will start met2's audio precisely when the click is heard.

yield WaitForEndOfFrame ensures nothing else is done at the same time, which isn't at all what it was meant for but works.

AudioVelocityUpdateMode might have an impact, I'm not 100% sure. It is by default set to Dynamic on objects without rigidbodies, and since I don't use rigidbodies much these days... Try Dynamic if you're having trouble. And do let me know of your precise use case if you're still struggling!

 var met2 : GameObject;
 
 private var offset : int;
 
 function Update(){
      if(Input.GetKeyDown("space")){
          
           if(met2.audio.isPlaying == false){
                yield WaitForEndOfFrame;
                offset = audio.clip.samples - audio.timeSamples;
                met2.audio.Play(offset);
           }
           else{
                met2.audio.Stop();
           }
      }
 }
Comment
Add comment · 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
0

Answer by memetic-arts · Feb 17, 2012 at 06:46 AM

This sounds very promising. I'm still a bit green in coding for U3D though . . .would you mind posting your final code? I'm just not sure where or how you are setting AudioVelocityUpdateMode.Fixed, or where yield WaitForFixedUpdate is being called.

Thanks in advance for the help!

Comment
Add comment · 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
0

Answer by memetic-arts · Feb 22, 2012 at 03:28 PM

Thanks gregzo, it was worth the wait because it worked! I've only tried about five separate clips so far, but they all seem to be synced and holding steady, after five minutes of continuous playback.

I actually only used the yield WaitForEndOfFrame statement . . . still wasn't sure what to do with AudioVelocityUpdateMode, or where to put it. If you could expound, that would be awesome.

I guess it's only fair for me to post my code. My 'usecase' is to set up an environment consisting of any number of zones/objects that trigger individual tracks -- that is discrete musical segments, e.g. bass, drums, etc. So obviously, those must all be in sync with each other.

In looking for a somewhat "elegant" and reusable solution, I've arrived at an approach in which there is a single "guide" track (a metronome, effectively), which is global, and is attached to my FPC. It starts running when the first zone/object is triggered. Each zone/object has its own audio source, and when triggered, polls the metronome for its time position in samples, and if they're not the same (which they usually wouldn't be), sets itself to the metronomes position value.

And that's it. I don't know if this is the "standard" way to do it or not -- I haven't seen any definitive method posted anywhere -- but it seems to work. Here's the code:

audioControl.js (attached to the FPC)

 var started = false;
 var guide : AudioClip;
 audio.clip = guide;
 
 function syncAudio(loop){
     loop.timeSamples = audio.timeSamples;
     // for some reason, the first object to call this function never wants
     // to fall into sync using the above statment, so we must reiterate below.
     // don't ask me why!
     if(loop.timeSamples!=audio.timeSamples){
         yield WaitForEndOfFrame;
         loop.timeSamples = audio.timeSamples;
     }
 }


=============================

TriggerScript.js (attached to every object that has a triggerable audio source. Note that it references variables/functions in the audioControl script)

 var target : Collider;
 var mySound : AudioClip;
 
 function OnTriggerEnter(cubeTrigger : Collider){
      if (cubeTrigger == target){
           audio.clip = mySound;
           var fpc : GameObject;
           // POV is the name of my FPC object
           fpc = GameObject.Find("POV");
           var ctrl =  fpc.GetComponent(audioControl);
           if (!audio.isPlaying){            
                audio.Play();
                if(ctrl.started==false){
                     fpc.audio.Play();
                     ctrl.started = true;
                }
                else{
                    ctrl.syncAudio(this.audio);
            }
           }     
      }
 }

====================

Thanks again for the help, gregzo, much appreciated it. If you see any improvements that could/should be made on the above, I'd gladly welcome your input!

Cheers,

==rr

Comment
Add comment · Show 2 · 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 gregzo · Mar 06, 2012 at 12:34 AM 0
Share

Hi! One problem I see, unrelated to audio, is your getComponent call. If you know you will need the component, you should cache a reference to it ins$$anonymous$$d of getting it everytime it is required! Second, I notice you are adjusting the timeSamples of your loop after playing. Better to know first at which sample you want to start playing, and when(using play(offset in samples)).

avatar image memetic-arts · Mar 06, 2012 at 05:14 AM 0
Share

re: caching ref to getComponent -- sounds like a good idea, but I have no idea how to do that . . . please enlighten me! ;-)

re: setting the start point in the loop before invoking Play() -- d'oh!! you're absolutely right!

thanks again (and again!)!!

avatar image
0

Answer by gregzo · Feb 22, 2012 at 10:34 PM

Be careful with your use of timeSamples. It is a member variable of an AudioSource, not of a clip. You should check audio.timeSamples... And use #pragma strict at the top of all your scripts, it will forbid this kind of misuse. Also, yield WaitForEndOfFrame somehow doesn't always give the best results for me (I'm still using Unity 3.5 RC1). It's always worth trying both with and without...

About AudioVelocityUpdateMode, I can't tell you much more since I don't use it at all in my current projects. No time to do some precise testing, unfortunately... I'm not a pro at all, just tried everything I could think of and stuck to the most functional solution!

Good luck and don't hesitate to ask more. And do practise strict typing, I assure you it will help a lot!

Comment
Add comment · Show 3 · 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 memetic-arts · Feb 25, 2012 at 03:57 AM 0
Share

gregzo, thanks for the tips, really appreciate that. But since, as you implied, #pragma strict now causes my script to fail, I'm not sure how to pass a reference to the newly-triggered AudioSource to the metronome script, e.g. how to properly compare timeSamples. Any thoughts on that?

Thanks again . . .

avatar image memetic-arts · Feb 25, 2012 at 04:00 AM 0
Share

and just to clarify, in the syncAudio function, the argument "loop" is intended to be a reference to the Audio Source, which I thought I was passing from onTriggerEnter as this.audio. Obviously that's not working, so will continue to experiment.

avatar image memetic-arts · Feb 25, 2012 at 05:29 AM 0
Share

Ha, figured it out, I think. $$anonymous$$ight not be the most efficient in terms of performance, ultimately, but works for now. Ins$$anonymous$$d of trying to pass a reference to the AudioSource component itself, I'm passing the name of the GameObject to which it is attached. Then, in the controller script, am just using Find to access the Audio Source through the Game Object.

So, from the trigger script:

ctrl.syncAudio(this.gameObject.name);

And, in the control script, where objName is the argument/value passed from the function call in the trigger script:

var zObj : GameObject;

zObj = GameObject.Find(objName);

zObj.audio.timeSamples = audio.timeSamples;

$$anonymous$$ake sense?

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

6 People are following this question.

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

Related Questions

How to send audio to a specific channel? 1 Answer

How to make two audio tracks play in sync? 2 Answers

Screenshot Movie with Audio Capture 1 Answer

Music Visualiser Troubles 0 Answers

Synchronising Audio 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