iPhone Синхронизация временной последовательности с музыкой - PullRequest
0 голосов
/ 26 октября 2009

Я использую AVAudioPlayer для воспроизведения музыки в приложении для iPhone.

В классе, который я написал, у меня есть массив, который содержит случайные возрастающие целые числа. (2, 4, 9, 17, 18, 20, ...) Эти целые числа представляют времена в песне, в которые должно произойти определенное событие. Поэтому, если вы возьмете вышеуказанный массив, через 2 секунды воспроизведения песни, должен быть вызван какой-то метод. Через 4 секунды должен быть вызван другой метод. И так далее.

Я пытался использовать повторяющийся NSTimer:

NSTimer *myTimer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(timerTick) userInfo:nil repeats:YES];

Каждый раз при запуске проверяется, совпадают ли значения аудиоплеера и текущего индекса массива:

- (void) timerTick {
   if([[myArray objectAtIndex:currentIndex] intValue] == (int)(player.currentTime)) {
   //here the event-method is called
   currentIndex++;
   }
}

Этот код действительно работает, но только в течение некоторого времени. Однако через некоторое время myTimer и таймер, который управляет музыкальным проигрывателем, не синхронизированы. Поэтому он пропускает элемент myArray и начинается бесконечный цикл. Я не знаю точно, почему они не синхронизированы, но я думаю, что это может быть из-за того, что таймер и проигрыватель не запускаются в одно и то же время или, возможно, из-за коротких задержек производительности.

Я думаю, что должен подходить к этому совершенно по-другому. Наблюдает ли ключ-значение способ сделать это? Я мог бы добавить свой класс в качестве наблюдателя к объекту player, чтобы он получал уведомления при изменении значения player.currentTime. Но это приведет к отправке МНОГО уведомлений, и я думаю, что это будет очень плохо для производительности.

Любая помощь высоко ценится!

Ответы [ 3 ]

1 голос
/ 26 октября 2009

Хорошо, вот мое решение: я нашел приложение с открытым исходным кодом, которое выполняет почти то же самое, что и мое приложение, что мне очень помогло. Я собираюсь придерживаться кода, который у меня уже есть, с небольшой модификацией он должен быть достаточно точным для моих целей. Вот оно:

currentIndex = 0;
myTimer = [NSTimer scheduledTimerWithTimeInterval:0.01 target:self selector:@selector(timerTick) userInfo:nil repeats:YES];


- (void) timerTick {
 if(timerRunning){


     if([[myArray objectAtIndex:currentIndex] intValue] <= (int)(player.currentTime*100)) { 
         //some event code
         currentIndex++;
     }
 }
}

Важное изменение от == до <= в условии if. Когда он становится асинхронным и пропускает элемент myArray, ошибка исправляется в следующую сотую секунду. Это достаточно хорошо. </p>

Спасибо за вашу помощь!

0 голосов
/ 26 октября 2009

Синхронизация с реальным миром с музыкой очень сложна, потому что пользователи могут заметить несинхронизацию всего за одну десятую секунды или меньше. Вы можете обнаружить, что AVAudioPlayer прост для того, что вам нужно. Возможно, вам придется контролировать скорость воспроизведения музыки с помощью AudioQueueServices , чтобы можно было синхронизировать музыку с кодом, а не наоборот. Вы можете увидеть, как запускается ваш код, а затем запускать методы до того, как музыка действительно начнет воспроизводиться. Сделано умело, это синхронизирует музыку большую часть времени.

0 голосов
/ 26 октября 2009

Может случиться так, что таймеры разумно синхронизированы, но выполнение вашего кода занимает много времени (т.е. дольше, чем 1 секунда).

Не могли бы вы просто использовать таймер музыкального проигрывателя и создавать поток каждый раз, когда должно происходить событие? Таким образом, таймер остается непрерывным, и ваш поток будет делать то, что ему нужно (скажем, тяжелые вещи).

Если вам действительно нужны два таймера, я думаю, вы могли бы создать фоновые потоки, которые синхронизировали бы эти два таймера, но я думаю, что у вас возникли проблемы ..

...