Простой метроном - PullRequest
       4

Простой метроном

1 голос
/ 16 сентября 2011

Я пытаюсь написать простой метроном, воспроизводя системный звук каждые 0,25 секунды.Я использую GCD для воспроизведения кликов в отдельном потоке, но игра идет неравномерно, иногда клики появляются в виде двух быстрых ударов, за которыми следует медленный удар.Я записал время, когда оператор if в цикле выполняется и имеет право на 0,25 секунды.Я надеюсь, что мне не нужно использовать Audio Queue Services.Есть предложения?

- (IBAction)start:(id)sender 
{
    dispatch_queue_t clickQueue; // the queue to run the metronome clicker
    dispatch_queue_t mainQueue; // I access the main queue to demonstrate how to change UIKit items
    //clickQueue = dispatch_queue_create("clickQueue", NULL);
    clickQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);
    mainQueue = dispatch_get_main_queue();
    dispatch_async(clickQueue, ^{
        double timeWas = [NSDate timeIntervalSinceReferenceDate];
        //delay by a 1/10 of a second so the first few clicks don't bunch up.
        double timeIs = [NSDate timeIntervalSinceReferenceDate]  - 0.1; 
        // playing starts out as NO because it gets switched at the end of the loop
        // and the PlaySystemSound block isn't off the queue yet. There is probably a
        // better way to do this.
        while (playing) {
            timeIs = [NSDate timeIntervalSinceReferenceDate] ;
            if ((timeIs - timeWas) > (60.0/240)) {
                AudioServicesPlaySystemSound(sound);
                timeWas = timeIs;
                // I want to flast the 200 label between orange and black but I have to access
                // user interface objects from the queue that they are running in, usually the
                // main queue.
                dispatch_async(mainQueue, ^{
                    if (flash)
                        [bpm setTextColor:[UIColor orangeColor]];
                    else
                        [bpm setTextColor:[UIColor blackColor]];
                    flash = !flash;
                });
            }
        }
    });
    playing = !playing;
    if (playing) 
        [startButton setTitle:@"Stop" forState:UIControlStateNormal];
    else
        [startButton setTitle:@"Start" forState:UIControlStateNormal];
}

Ответы [ 5 ]

3 голосов
/ 16 сентября 2011

Используйте NSTimer для времени и AVFoundation для звуков.

1 голос
/ 16 сентября 2011

Люди, которые собрали http://www.metronomeonline.com/, довольно хорошо справились с проблемами синхронизации, хотя они не разрабатывали для какого-либо конкретного оборудования / ОС.Я полагаю, что они сделали это путем создания предварительно записанных файлов .wav / .mp3 за несколько секунд для каждого темпа , а затем зациклили их.Скорость петли рассчитывается с точностью до темпа.Делая событие цикла единственным, что зависит от синхронизации клиента, они уменьшают ошибки синхронизации.

0 голосов
/ 19 сентября 2011

Я бы попробовал использовать:

void dispatch_after(
   dispatch_time_t when,
   dispatch_queue_t queue,
   dispatch_block_t block);

Вы также можете прочитать http://atastypixel.com/blog/experiments-with-precise-timing-in-ios/, что очень интересно в вашем контексте ...

0 голосов
/ 19 сентября 2011

Я сам пошел по тому же маршруту в одной точке с моим приложением метронома. К сожалению, вы никогда не получите желаемой точности с высокоуровневыми API, такими как PlaySystemSound - они просто не реагируют достаточно быстро.

Скорее всего, если вам нужна истинная точность с вашими темпами и звуками, которые вы воспроизводите в качестве «щелчков», вы захотите использовать Аудиоустройства - возможно, вы сможете обойтись без Audio Queue Services - я не Я не слишком много экспериментирую с этим, осознавая, что в какой-то момент мне нужно будет получить низкий уровень, и решив сделать все возможное.

0 голосов
/ 16 сентября 2011

Лучшим подходом было бы использование повторяющегося NSTimer с требуемым интервалом.Ваш метод сбивает процессор.

...