准确重复iPhone声音

准确重复iPhone声音,iphone,objective-c,xcode,avaudioplayer,nsthread,Iphone,Objective C,Xcode,Avaudioplayer,Nsthread,我正在使用一个应用程序,它需要以60毫秒的间隔播放声音“轻拍”(每分钟播放1000次轻拍)。当我超过大约120毫秒的间隔(每分钟500次敲击)时,声音变得非常不稳定,似乎彼此堆积在一起 我正在使用的声音字节是10毫秒长,我有一个线程计时器,它以20毫秒的间隔运行。我正在使用AVAudioPlayer播放声音,并尝试了wav、caf和m4a格式。我已经用NSLog输出进行了测试,以查看AVAudioPlayer何时被触发,计时器循环何时轮询……所有时间似乎都足够准确 我在viewDidLoad()

我正在使用一个应用程序,它需要以60毫秒的间隔播放声音“轻拍”(每分钟播放1000次轻拍)。当我超过大约120毫秒的间隔(每分钟500次敲击)时,声音变得非常不稳定,似乎彼此堆积在一起

我正在使用的声音字节是10毫秒长,我有一个线程计时器,它以20毫秒的间隔运行。我正在使用AVAudioPlayer播放声音,并尝试了wav、caf和m4a格式。我已经用NSLog输出进行了测试,以查看AVAudioPlayer何时被触发,计时器循环何时轮询……所有时间似乎都足够准确

我在viewDidLoad()方法中添加了音频会话处理,如下所示:

 [[AVAudioSession sharedInstance]
 setCategory: AVAudioSessionCategoryPlayback
 error: &setCategoryError];
这是我在自己的线程中运行的计时器循环:

NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 

// Give the sound thread high priority to keep the timing steady.
[NSThread setThreadPriority:1.0];

while (running) {     // loop until stopped. 
    [self performSelectorOnMainThread:@selector(playOutput) withObject:nil waitUntilDone:NO];

    // An autorelease pool to prevent the build-up of temporary objects.
    NSAutoreleasePool *loopPool = [[NSAutoreleasePool alloc] init];

    NSDate *curtainTime = [[NSDate alloc] initWithTimeIntervalSinceNow:sleepValue];
    NSDate *currentTime = [[NSDate alloc] init];
    // Wake up periodically to see if we've been cancelled. 
    while (running && ([currentTime compare:curtainTime] == NSOrderedAscending)) { 
        [NSThread sleepForTimeInterval:0.015];
        [currentTime release];
        currentTime = [[NSDate alloc] init];
    }

    [curtainTime release]; 
    [currentTime release]; 
    [loopPool drain];
}
[pool drain];
以下是我初始化AVAudioPlayer的方式:

NSString *beatOne = @"3h";
NSString *beatOneSoundFile = [[NSBundle mainBundle]
                              pathForResource:beatOne ofType:@"caf"];
NSURL *beatOneURL = [[NSURL alloc] initFileURLWithPath:beatOneSoundFile];
beatPlayerOne = [[AVAudioPlayer alloc]initWithContentsOfURL:beatOneURL error:nil];
beatPlayerOne.delegate = self;
beatPlayerOne.currentTime = 0;
[beatPlayerOne prepareToPlay];
[beatOneURL release];
这里是播放音频播放器的地方:

[beatPlayerOne pause];
beatPlayerOne.currentTime = 0;
[beatPlayerOne play];

提前感谢您的帮助…

您应该尽可能避免[NSThread Sleep]。请改用NSTimer:

[NSTimer scheduledTimerWithTimeInterval:(0.015) target:self selector:@selector(timerfn) userInfo:nil repeats:NO];
//the @selector(timerfn) is which function it calls
如果要继续播放声音,请在它调用的函数中调用此计时器

将计时器保存到一个变量,如下所示:

 mytimer=[NSTimer scheduledTimerWithTimeInterval:(0.015) target:self selector:@selector(timerfn) userInfo:nil repeats:YES];
和使用:

 [mytimer invalidate];
    mytimer=nil;
杀了它

然后只需播放函数中的声音。你也可以使用[NSTimer alloc]和[mytimer release],我想

此外,每秒66.6次的调用似乎有些过分。

NSTimer(以及与此相关的NSThread sleep)不是可靠的“时钟计时”机制。如果有什么东西阻塞了主线程,运行循环将不会结束,直到它解除阻塞,计时器和线程睡眠将不会被及时调用

此外,NSTimer上的分辨率最多为1/30秒,尽管框架没有承诺其发射的规律性。正如你所看到的,这是不正常的。如果你的邮件应用程序在后台启动,它很可能会把你所有花哨的嗡嗡声都弄得乱七八糟


我认为,您最好生成包含不同点击速度的较长声音文件,并减少其触发频率。

正如Dan Ray所说,
NSTimer
NSThread
对于精确计时来说是不可靠的。如果我是你,我会使用一个-它将通过输入回调请求音频缓冲区,你将填充它们。如果您及时响应,它将以准确地硬件采样率请求并复制这些缓冲区,因此您可以进行一些简单的计算,以确定轻敲的时间,并从文件或存储在数组或向量中的样本填充每个缓冲区。如果您选择直接从文件开始,则可以使用
AudioFileReadPackets
填充

这将是一个多一点的工作,但它的多功能和强大得多。您可以使用音频队列进行音频的实时合成和处理,因此只要您在截止日期前完成,它们的计时就非常精确。如果您对处理器的使用非常小心,那么每隔几毫秒就会有一次轻敲声,而不会出现任何问题

看一看示例应用程序,开始使用音频队列。对于这类事情也很有用,您可以通过回调向他们提供数据,但是他们需要更多的设置,学习曲线更陡峭


祝你好运

也许你可以考虑播放包含10次敲击的音频文件?最终,敲击之间的间隔将是可调的。它需要能够处理每分钟最多1000次点击(如果可能的话更高),但最终,您会遇到一个“量子”问题,即等待时间太接近可识别的最小时间量(即毫秒)。感谢所有良好的输入。事实证明,越简单越好。我已经意识到NSTimer的缺点,所以我认为我的线程计时循环就足够了。不幸的是,NSTimer在精度方面非常不可靠。与其他语言(C++、Java等)一样,线程可能非常有用,但您需要在内部处理精度级别。我认为60毫秒的点击率是每秒16.66667次,我不知道。谢谢我是从0.015开始的,不是60毫秒。。。所以我们都是对的!