Search Unity

BPM accuracy, hope in 3.5? Soren?

Discussion in 'Editor & General Support' started by gregzo, Dec 17, 2011.

  1. gregzo

    gregzo

    Joined:
    Dec 17, 2011
    Posts:
    795
    Sorry for all the edits, i'm getting all sorts of weirdness trying to do this on my iPad...

    Thanks for the replys. All boxes checked, best latency, high fixed time, decompress on load.

    Sorry for the typo, I get a delay of up to .15s from time to time, even in an empty scene doing nothing, even in a built version.

    Just saw the fract sequencer demo on Vimeo, if it's all done in Unity, without interfacing with another audio engine, there's hope! Do you know how they did it?

    Last edit : after looking more closely, the fract sequencer is not a true sequencer, it has really low res. Accurate, but bpm baked in the samples?
     
    Last edited: Dec 17, 2011
  2. antenna-tree

    antenna-tree

    Joined:
    Oct 30, 2005
    Posts:
    5,324
    4 - The possibility that the limitation is in your coding? You admit that you're not an experienced programmer ;-)

    Isn't 15 milliseconds around a 128th note at 120 BPM though? That seems like enough granularity to me. Anyway, I'll poke Søren about this thread and maybe he has some insights. In the meantime here's the guys working on Fract and the sequencer they're working on in case you haven't heard of the game before.
     
  3. hippocoder

    hippocoder

    Digital Ape

    Joined:
    Apr 11, 2010
    Posts:
    29,723
    Did you set sound to "best latency" ? It could be you're getting a mild delay from that.
     
  4. gregzo

    gregzo

    Joined:
    Dec 17, 2011
    Posts:
    795
    Hi to all!
    I am trying to achieve a stable firing of audioclips, but cannot do better than .15s accuracy. I've tried InvokeRepeating, coroutines, the delay by samples method described here http://forum.unity3d.com/threads/78003-Audio-stepsequencer-and-they-said-it-couldnt-be-done! , and even FixedUpdate, to no avail.

    This is a huge downer for me as it basicaly ruins any hopes of building a serious step sequencer. I am not an experienced programmer, so writing a plugin/bridging to an external audio engine is out of the question.

    I see three solutions, in order of preference:

    1-Unity 3.5 or 3.6 solves this, hurray!
    2-There is a plugin somewhere I haven't found, and someone kindly points me to it, yippee!
    3-Another game engine would suit my needs better, darn, I love Unity...

    Many thanks for your help. A comment from Soren would be greatly appreciated too!

    P.S.: there are Unity made step sequencers out there, but they are not more precise. .015s is unfortunately enough to give a beats/patterns a quirky feel... Not a criticism of the developpers behind these, these are great apps, just limited by the platform they were developed on.
     
    Last edited: Dec 17, 2011
  5. antenna-tree

    antenna-tree

    Joined:
    Oct 30, 2005
    Posts:
    5,324
    You swapped your posts while editing... not sure how you pulled that off :p

    I'm pretty sure the sequencer is a "true sequencer" in the fact that they are triggering samples based on sequences that are interactive/editable in the gameplay. You can see in that video that he is dragging different audio samples into the array that are one note hits and not phrases. When they claim that this sequencer can handle arbitrary sequences up to 250 BPM it makes it sound like it's pretty tight. Maybe contacting Richard and seeing if he has any tips or advice would be helpful.
     
  6. gregzo

    gregzo

    Joined:
    Dec 17, 2011
    Posts:
    795
    Ok, after a good night's sleep, I've found a workable solution: grouping steps in beats (4 steps per beat), and offsetting all four steps of a beat at once. It's the tightest I've managed (still minute delays, but perfectly workable till up to 480 steps per minute, maybe more).

    -downside : any edit of a step while it's playing will only sound the next time around...

    -from what I've seen, the ingame sequencer of fract (which looks awesome...) lets you change whole beats, not steps of a beat, so I suspect they might use the same trick... Will ask Richard!

    -Thanks a bunch for giving hope: didn't sleep much, but know that it's done, mood's greatly improved. Got 3 sequencers tightly running at different speeds in 3d, yippee!!!
     
  7. soren

    soren

    Joined:
    Feb 18, 2008
    Posts:
    123
    Hi Gregzo - sorry for the wait (been busy with 3.5),
    The average latency of the built-in mixer is ~50ms (*before* it's send off to the driver layer). Plus, .Play() can add a few ms of latency because it sample-"align"s all Play(s) in the same frame.
    There is no way to change this pre-3.5 Unity. This usually fine for gaming applications. For a sequencer this is probably too slow (I think the pro filter/effect vendors are usually aiming for ~25ms). Why do you need such a low latency (Do you have a on-screen keyboard or)?
    Anyway, in 3.5 you can set the samplerate and the size of the internal ringbuffer. So in theory you can get very low latency. But it's limited by the cpu/OS's ability to keep up with such a high mixer frequency.
    Furthermore, 3.5 gives a callback on the mixer thread enabling you to feed audio data directly to the mixer (and avoid context shift, buffer sync), that'll give you a lower latency as well.
    So basically, 3.5 could be the answer to your troubles (and it's out soon). But let me know more about your usecase, before I dismiss 3.4 completely.

    cheers,
    Søren
     
    Last edited: Dec 19, 2011
  8. steego

    steego

    Joined:
    Jul 15, 2010
    Posts:
    969
    Actually quite lower than that. Around 10-12ms is noticeable when playing some kind of instrument. Most soft-synths and effects will have a much lower latency that that, it's usually the soundcard and drivers that are the bottleneck.

    With audio buffer access I might even look into writing a VST bridge plugin for Unity, using VST softsynths and effects directly would be really cool. Can we read from the buffer as well in 3.5 or is it write only?
     
  9. soren

    soren

    Joined:
    Feb 18, 2008
    Posts:
    123
    Read/write
     
  10. gregzo

    gregzo

    Joined:
    Dec 17, 2011
    Posts:
    795
    Soren, thanks for the reply! I am building a customizable step sequencer (meaning the user can alter the number of steps, not locked to 4 steps per beat in 4/4 time). Actualy, the aim is to have many sequencers running together, at different speeds(user defined) in 3d space. I've got 3 running tightly, now that I use the offset samples technique, but that lowers the realtime aspect of the sequencer ( once a beat has started, the user cannot change its content anymore since all samples inside that beat have already been fired). Ultimately, to have more sequencers running in parallel, I'll need to bounce the output of the ones the user is not tinkering with to reduce the number of audiosources ( each sequencer requires 20 audiosources minimum). I'm eager to see what 3.5 has in store for us! Will there be new functions to use, or will it have to be done with .NET libraries? I dream of a OutputToWav(Audiosource[ ]) function...

    P. S. 50 ms is a tenth of a beat at 120 bpm, perfectly audible...
     
  11. Evil-Dog

    Evil-Dog

    Joined:
    Oct 4, 2011
    Posts:
    134
    Hi Soren, about that audio callback to feed audio data directly in Unity 3.5, are there any examples how to use it? What about AudioClip::SetData and GetData? Any documentation about that?
    Any pointers would be appreciated.
    Thanks
     
  12. soren

    soren

    Joined:
    Feb 18, 2008
    Posts:
    123
    Hi,
    Have you looked at the local documentation (Documentation/ScriptReference/index.html) shipping with Unity 3.5? There should is example for both GetData/SetData and OnAudioFilterRead

    (copy-pasted-from-the-docs) :

    AudioClip.GetData

    function GetData (data : float[], offsetSamples : int) : void
    Description
    Fills an array with sample data from the clip. The samples are floats ranging from -1.0f to 1.0f. The sample count is determined by the length of the float array.

    Use offsetSamples to start the read from a random position in the clip. If the read length from the offset is longer than the clip length, the read will wrap around and read the remaining samples from the start of the clip.

    JavaScript
    // Read all the samples from the clip and half the gain
    function Start () {
    var samples = new float[audio.clip.samples * audio.clip.channels];
    audio.clip.GetData(samples, 0);
    for (var i = 0; i < samples.Length; ++i)
    samples = samples * 0.5f;
    audio.clip.SetData(samples, 0);
    }

    MonoBehaviour.OnAudioFilterRead

    function OnAudioFilterRead () : void
    Description
    If OnAudioFilterRead is implemented, Unity will insert a custom filter into the audio DSP chain.

    The filter is inserted in the same order as the MonoBehaviour script is shown in the inspector. OnAudioFilterRead is called everytime a chunk of audio is routed thru the filter (this happens frequently, every ~20ms depending on the samplerate and platform). The audio data is an array of floats ranging from [-1.0f;1.0f] and contains audio from the previous filter in the chain or the AudioClip on the AudioSource. If this is the first filter in the chain and a clip isn't attached to the audio source this filter will be 'played'. That way you can use the filter as the audio clip, procedurally generating audio.

    If OnAudioFilterRead is implemented a VU meter will show up in the inspector showing the outgoing samples level. The process time of the filter is also measured and the spent milliseconds will show up next to the VU Meter (it turns red if the filter is taking up too much time, so the mixer will starv audio data). Also note, that OnAudioFilterRead is called on a different thread from the main thread (namely the audio thread) so calling into many Unity functions from this function is not allowed ( a warning will show up ).

    See Also: Audio Filters

    // This custom filter controls the gain by filtering the samples by multiplying each sample with a <i>gain</i> parameter.

    public var gain : float;

    function OnAudioFilterRead(var data:float[], var channels:int) {
    for (var i = 0; i < data.Length; ++i)
    data = data * gain;
    }
     
  13. Evil-Dog

    Evil-Dog

    Joined:
    Oct 4, 2011
    Posts:
    134
    Oh thanks Soren, I didn't see it had local documentation. Your quick reply is much appreciated! I shall look into it! Cheers
     
  14. gregzo

    gregzo

    Joined:
    Dec 17, 2011
    Posts:
    795
    Hi to all! Looking forward to 3.5's audio capabilities, but still having some trouble with 3.4. I've narrowed down the problem to the following situation:

    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 cources 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();
    }
    }
    }

    Am I doing something wrong? Because 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.4, Windows XP, audio settings to best latency, decompress on load, file is a wav (2d sound, but the same applies to 3d sounds).

    My project is nearly done, and this is the one issue I do not know what to do with... Any help/hope would be greatly appreciated!

    Many thanks,

    Gregzo