How to program a real-time accurate audio sequencer on the iphone?

后端 未结 9 694
北荒
北荒 2021-01-30 02:56

I want to program a simple audio sequencer on the iphone but I can\'t get accurate timing. The last days I tried all possible audio techniques on the iphone, starting from Audio

9条回答
  •  半阙折子戏
    2021-01-30 03:08

    You've had a few good answers here, but I thought I'd offer some code for a solution that worked for me. When I began researching this, I actually looked for how run loops in games work and found a nice solution that has been very performant for me using mach_absolute_time.

    You can read a bit about what it does here but the short of it is that it returns time with nanosecond precision. However, the number it returns isn't quite time, it varies with the CPU you have, so you have to create a mach_timebase_info_data_t struct first, and then use it to normalize the time.

    // Gives a numerator and denominator that you can apply to mach_absolute_time to
    // get the actual nanoseconds
    mach_timebase_info_data_t info;
    mach_timebase_info(&info);
    
    uint64_t currentTime = mach_absolute_time();
    
    currentTime *= info.numer;
    currentTime /= info.denom;
    

    And if we wanted it to tick every 16th note, you could do something like this:

    uint64_t interval = (1000 * 1000 * 1000) / 16;
    uint64_t nextTime = currentTime + interval;
    

    At this point, currentTime would contain some number of nanoseconds, and you'd want it to tick every time interval nanoseconds passed, which we store in nextTime. You can then set up a while loop, something like this:

    while (_running) {
        if (currentTime >= nextTime) {
            // Do some work, play the sound files or whatever you like
            nextTime += interval;
        }
    
        currentTime = mach_absolute_time();
        currentTime *= info.numer;
        currentTime /= info.denom;
    }
    

    The mach_timebase_info stuff is a bit confusing, but once you get it in there, it works very well. It's been extremely performant for my apps. It's also worth noting that you won't want to run this on the main thread, so dishing it off to its own thread is wise. You could put all the above code in its own method called run, and start it with something like:

    [NSThread detachNewThreadSelector:@selector(run) toTarget:self withObject:nil];
    

    All the code you see here is a simplification of a project I open-sourced, you can see it and run it yourself here, if that's of any help. Cheers.

提交回复
热议问题