Pergunta

Eu estou usando AVAudioPlayer para tocar música no meu iPhone app.

Em uma classe que eu escrevi Eu tenho uma matriz que contém inteiros ascendentes aleatórios. (2, 4, 9, 17, 18, 20, ...) Estes números inteiros representam vezes na canção em que um determinado evento deve ocorrer. Então, se você tomar a matriz acima, após 2 segundos da música tocando, algum método deve ser chamado. Após 4 segundos, um outro método deve ser chamado. E assim por diante.

Eu tentei usar um NSTimer repetir:

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

Toda vez que ele é acionado, ele verifica se o valor da Audioplayer e dos ArrayIndex atuais são os mesmos:

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

Este código realmente funciona, mas apenas por algum tempo. Depois de algum tempo no entanto, myTimer eo temporizador que controla a MusicPlayer estão fora de sincronia. Então, ele perde um elemento de myArray e infinidades começa laço. Eu não sei exatamente por que eles ficam fora de sincronia, mas acho que pode ser porque o temporizador e o jogador não está sendo iniciado exatamente ao mesmo tempo ou talvez por causa de defasagens de desempenho curtas.

Eu acho que tem que abordar isso de uma maneira totalmente diferente. É key-value observando uma maneira de fazer isso? Eu poderia acrescentar a minha classe como um observador para o objeto jogador, para que ele seja notificado quando o valor player.currentTime muda. Mas isso iria causar uma série de notificações para ser enviado e eu acho que seria muito ruim para o desempenho.

Qualquer ajuda muito apreciada!

Foi útil?

Solução

Ok aqui está a minha solução: Eu encontrei um aplicativo de código aberto que faz quase a mesma coisa que meu aplicativo deve fazer, o que me ajudou muito. Vou ficar com o código que já tem, com uma pequena modificação deve ser suficiente preciso para os meus propósitos. Aqui está:

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++;
     }
 }
}

A mudança importante é a partir == para <= na condição se. Quando fica assíncrona e perde um elemento de myArray, o erro seja corrigido o próximo centésimo de segundo. Isso é bom o suficiente.

Obrigado por sua ajuda!

Outras dicas

Pode ser que os temporizadores são razoavelmente em sincronia, mas o seu código apenas leva muito tempo para executar (ou seja: mais tempo, então 1 segundo).

Não foi possível que você acabou de usar o temporizador do musicplayer, e gerar um segmento cada vez que um evento deve ocorrer? Desta forma, as estadias temporizador ininterrupto, e seu segmento vai fazer o que ele precisa fazer (digamos que o material pesado).

Se você reall y necessidade dois temporizadores, eu acho que você poderia criar um fundo tópicos que mantém esses dois temporizadores em sincronia, mas eu acho que você está pedindo para ter problemas lá ..

sincronização mundo real com a música é muito difícil porque os usuários podem notar mis-sincroniza de apenas um décimo de segundo ou menos. Você pode achar que AVAudioPlayer é simples para o que você precisa. Você pode ter que controlar a taxa a música toca usando AudioQueueServices de modo que você pode sincronizar a música para o código em vez do contrário. Você pode ver o tempo para disparar seu código chegando e, em seguida, iniciar os métodos antes de a música realmente joga. Feito habilmente isso iria sincronizar a música na maioria das vezes.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top