我试图通过每0.25秒播放一次系统声音来编写一个简单的节拍器。我使用GCD来播放单独一个帖子上的点击,但是播放是不均匀的,点击有时是两个快节拍,然后是慢节拍。我记录了循环中if语句执行的时间,以及0.25秒的权限。我希望我不必使用音频队列服务。有什么建议吗?
- (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];
}
答案 0 :(得分:3)
当时使用NSTimer,声音使用AVFoundation。
答案 1 :(得分:1)
将http://www.metronomeonline.com/放在一起的人们在处理时序问题方面做得非常好,尽管他们没有针对任何特定的硬件/操作系统进行开发。我相信他们这样做的方法是为每个节奏创建预先录制的.wav / .mp3文件几秒钟,然后循环播放。循环速率计算为速度准确。通过使循环事件成为唯一依赖于客户端时序的事件,它们可以减少时序错误。
答案 2 :(得分:0)
更好的方法是使用具有所需间隔的重复NSTimer。你的方法会搅动CPU。
答案 3 :(得分:0)
我用我的节拍器应用程序自己一路走下同一条路线。不幸的是,使用像PlaySystemSound这样的高级API,你永远无法获得所需的精度 - 它们的反应速度不够快。
很可能,如果你想要你的节奏真正的精确度和你作为“点击”播放的声音,你会想要使用音频单元 - 你可能能够摆脱音频队列服务 - 我没有我没有多尝试,意识到无论如何我都需要在某个时候达到低水平,并选择全力以赴。
答案 4 :(得分:0)
我会尝试使用:
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/,这在您的背景中非常有趣......