Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Using audio-rate metronome for sound clip triggering

Discussion in 'Scripting' started by seejayjames, Dec 8, 2013.

  1. seejayjames

    seejayjames

    Joined:
    Jan 28, 2013
    Posts:
    687
    Hi all, been searching awhile on this and *sort of* understand it, but keep running into various problems.

    Basically I want to use an audio-rate metronome, just as in the docs at

    http://docs.unity3d.com/Documentation/ScriptReference/AudioSettings-dspTime.html

    This is working fine and sounds very solid, and I plan to make it as stripped-down as possible---no click, no need to write data into it, I just want that rock-solid TICK. (BTW if anyone has a streamlined version of that, I'd like to see it, it's been a little tricky to chip away the pieces of the example and still have everything work...still wrapping my head around the audio-rate functions.)

    The issue is then: how do you get the tick "out of" the OnAudioFilterRead() function? If I increment a counter, the numbers are all over the place---gradually increasing overall, but jumping back and forth between two levels (at least according to Debug.Log which I know I shouldn't use in there, but what's the other option?)...if I try to send the tick "alert" to another function, so it can increment there, same issue. I need to increment the tick so sounds can play every 8 ticks, every 16, etc. using modulus, which can make for some great sequencing possibilities.

    I imagine the issue has to do with other functions (in the main thread) running at a slower rate (and a more varied rate due to FPS inconsistency). Which is all OK as long as I can get this juicy, rock-solid TICK somewhere that I can trigger sounds to play.

    If there are any Max/MSP folks on here, it's analogous to using audio-rate timing for accuracy, and Max has a special object (edge~) which takes the tick from the audio realm to the scheduler realm. I'm trying to find the analogous element in unity and can't seem to get it!

    If there's a non-audio-rate solution, I'm happy to use that, but research tells me that these always drift and stutter too much for quality timing/sequencing.

    Thanks for any thoughts on this!

    C
     
  2. seejayjames

    seejayjames

    Joined:
    Jan 28, 2013
    Posts:
    687
    Update:

    With some more fiddling, got a bit further, not sure why I was running into the strange counter-incrementing issues before, but putting everything into one script seemed to fix it.

    Now I have the same rock-solid tick and an incrementing counter. I then use the count outside the OnAudioFilterRead() function to play the audio clips, as you can't call Play() from within it. Everything works as far as the counting (note: needed a boolean flag "tick_played" and a proxy counter variable to filter out repetitions, so the Play() wouldn't get triggered across multiple frames). But there is still some stuttering, which I imagine will only get worse on a mobile device. The generated "tick" within OnAudioFilterRead() is totally solid by comparison.

    So...any thoughts on how to bridge these two worlds? Or is it just not possible this way?

    I also thought of using my short drum clip as the audio clip, so that OnAudioFilterRead() would play it, but am not sure how to get that working. Probably that won't be a possibility anyway because the clips I plan to use are considerably longer than the data length that OnAudioFilterRead() uses.

    Thanks...!

    C
     
  3. willemsenzo

    willemsenzo

    Joined:
    Nov 15, 2012
    Posts:
    585
    I wish I had an answer for you, but I'm affraid not. Currently I'm playing audio in a sequence, by filling an array with audio data from different clips, and create a new clip from that. The timing is sample perfect, but getting this to work on variable bpm gets more complicated, because the ticktime also changes. I'm sure there are better/more efficient ways to go about this, but then again, I have no idea how. I'm trying the AudioSettings.dspTime example, if I find out how this works I'll let you know.
     
  4. seejayjames

    seejayjames

    Joined:
    Jan 28, 2013
    Posts:
    687
    Interesting approach. I'll definitely be looking into manipulating the sound arrays more in the future. I'm also using some very simple buffers and looping them to make sine, square, etc., which act as "drones" and don't need any special timing...these work great (I was very precise in making them, ensuring that the start and end points are the same, so no clicking when looping). But the main part of the scene that I'm envisioning will be able to play many notes from different locations, including simultaneously, all in steady rhythm that's determined by the metronome (ticking at 24x the rate of a "whole note", so modulus == 0 will work at 2, 3, 4, 6, 8, and 12).

    I tested it running with the fastest tick = 240 bpm (4 ticks per second) and it actually played fairly consistently, even on my tablet...though I worry about how various other devices would perform. I'd like to get up to 480 bpm as my fastest possible note, or 8 per second...not much need to go faster than that aurally anyway. Overall bpm would be shiftable up and down a bit to get different tempos, then the given bpm is divided up as described above.

    I guess I'll keep fiddling and making more audio clips to use while this issue (hopefully!) gets addressed...and if it's just not possible this way, maybe there's another one (PlayScheduled?) that will do the trick.
     
  5. seejayjames

    seejayjames

    Joined:
    Jan 28, 2013
    Posts:
    687
    bump...

    anyone with some ideas? just curious...still wondering about audio-rate "ticks" getting out of the audio thread and into the main thread, where they can trigger clips with accurate timing.

    If it has to be PlayScheduled() or some other method, that's fine, but was hoping for just a nice solid "tick" and to go from there...
     
  6. willemsenzo

    willemsenzo

    Joined:
    Nov 15, 2012
    Posts:
    585
    If you're still interested send me a PM, I figured out couple of things that make life easier :)
     
  7. Recluse

    Recluse

    Joined:
    May 16, 2010
    Posts:
    485
    Did you solve this? I'm doing something similar and have multiple audio clips playing in sync. I read the dspTime in OnAudioFilterRead and increment an int counter. When this is greater than 0 in Update() I broadcast a beat event to all subscribed listeners, triggering the step sequencer to advance in each audio source and play if set to.