Я хочу запрограммировать простой аудио секвенсор на iphone, но не могу получить точное время. В последние дни я попробовал все возможные звуковые приемы на iphone, начиная с AudioServicesPlaySystemSound и AVAudioPlayer и OpenAL до AudioQueues.
В моей последней попытке я попробовал звуковой движок CocosDenshion, который использует openAL и позволяет загружать звуки в несколько буферов, а затем воспроизводить их при необходимости. Вот основной код:
INIT:
int channelGroups[1];
channelGroups[0] = 8;
soundEngine = [[CDSoundEngine alloc] init:channelGroups channelGroupTotal:1];
int i=0;
for(NSString *soundName in [NSArray arrayWithObjects:@"base1", @"snare1", @"hihat1", @"dit", @"snare", nil])
{
[soundEngine loadBuffer:i fileName:soundName fileType:@"wav"];
i++;
}
[NSTimer scheduledTimerWithTimeInterval:0.14 target:self selector:@selector(drumLoop:) userInfo:nil repeats:YES];
В процессе инициализации я создаю звуковой движок, загружаю некоторые звуки в разные буферы и затем устанавливаю цикл секвенсора с помощью NSTimer.
аудио цикл:
- (void)drumLoop:(NSTimer *)timer
{
for(int track=0; track<4; track++)
{
unsigned char note=pattern[track][step];
if(note)
[soundEngine playSound:note-1 channelGroupId:0 pitch:1.0f pan:.5 gain:1.0 loop:NO];
}
if(++step>=16)
step=0;
}
Вот так и работает, как и должно, НО время шаткое и нестабильное. Как только происходит что-то еще (например, рисование в виде), оно перестает синхронизироваться.
Как я понимаю, звуковой движок и openAL буферы загружаются (в коде инициализации), а затем готовы немедленно начать с alSourcePlay(source);
- так что проблема может быть с NSTimer?
Теперь в магазине приложений есть десятки приложений звукового секвенсора, и у них есть точное время. I.g. "idrum" имеет идеальный стабильный ритм даже при 180 ударах в минуту, когда масштабирование и рисование сделаны. Так что должно быть решение.
У кого-нибудь есть идеи?
Заранее спасибо за любую помощь!
С уважением,
Walchy
Спасибо за ваш ответ. Это привело меня на шаг вперед, но, к сожалению, не к цели. Вот что я сделал:
nextBeat=[[NSDate alloc] initWithTimeIntervalSinceNow:0.1];
[NSThread detachNewThreadSelector:@selector(drumLoop:) toTarget:self withObject:nil];
В инициализации я сохраняю время для следующего удара и создаю новый поток.
- (void)drumLoop:(id)info
{
[NSThread setThreadPriority:1.0];
while(1)
{
for(int track=0; track<4; track++)
{
unsigned char note=pattern[track][step];
if(note)
[soundEngine playSound:note-1 channelGroupId:0 pitch:1.0f pan:.5 gain:1.0 loop:NO];
}
if(++step>=16)
step=0;
NSDate *newNextBeat=[[NSDate alloc] initWithTimeInterval:0.1 sinceDate:nextBeat];
[nextBeat release];
nextBeat=newNextBeat;
[NSThread sleepUntilDate:nextBeat];
}
}
В цикле последовательности я устанавливаю приоритет потока как можно выше и захожу в бесконечный цикл. После воспроизведения звуков я вычисляю следующее абсолютное время для следующего удара и отправляю поток в спящий режим до этого времени.
Опять же, это работает, и оно работает более стабильно, чем мои попытки без NSThread, но все равно шатко, если что-то происходит, особенно в GUI.
Есть ли способ получить ответы в реальном времени с помощью NSThread на iphone?
С уважением,
Walchy