为什么我的声音听起来不玩的时间? [英] Why are my audio sounds not playing on time?

查看:166
本文介绍了为什么我的声音听起来不玩的时间?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的一个应用程序有一个简单的节拍器式的功能,扮演一个滴答声的每分钟(BPM)指定的次数。我通过启动的NSTimer,从指定的BPM计算的间隔,即调用播放声音的方法这样做。

One of my apps has a simple metronome-style feature that plays a click sound a specified number of times per minute (bpm). I'm doing this by starting an NSTimer, with an interval calculated from the specified bpm, that calls a method that plays the sound.

如果我把一个NSLog的线入戏的方法,我可以看到的NSTimer准确地发射到大约1毫秒。但是,如果我录制声音输出到音频编辑器,然后测量点击之间的时间间隔,我可以看到,他们不是均匀分布的。例如,150 BPM,定时器触发间隔为400毫秒。但大多数的声音播放后395毫秒,拥有418后每毫秒第三或第四声音播放。

If I put an NSLog line into the play method, I can see that NSTimer is firing accurately to about 1 millisecond. However, if I record the sound output into an audio editor and then measure the interval between clicks, I can see that they are not evenly spaced. For example, with 150 bpm, the timer fires every 400 milliseconds. But most of the sounds play after 395 milliseconds, with every third or fourth sound playing after 418 milliseconds.

所以声音不会均匀地推迟,但相反,它们遵循较短和较长的时间间隔的图案。看来,如果内部监督办公室对于声音的时间较低的分辨率,并四舍五入每个声音事件到最近的点,或者四舍五入上下,以维持轨道上的整体。

So the sounds are not uniformly delayed, but rather, they follow a pattern of shorter and longer intervals. It seems as if the iOS has a lower resolution for timing of sounds, and is rounding each sound event to the nearest available point, rounding up or down as needed to keep on track overall.

我曾试图与系统声音,AVAudioPlayer和OpenAL的,并已经得到了所有三种方法同样的结果。每一种方法,我做的所有的设置视图时的负载,所以每次我播放的声音都是我所要做的就是发挥它。随着AVAudioPlayer,我试图用第二计时器以后每次播放声音时调用prepareToPlay,所以它被初始化,并准备去下一次,但得到了同样的结果。

I have tried this with system sounds, AVAudioPlayer and OpenAL and have gotten the exact same results with all three methods. With each method, I'm doing all the setup when the view loads, so each time I play the sound all I have to do is play it. With AVAudioPlayer, I tried calling prepareToPlay using a second timer after each time the sound plays, so it is initialized and ready to go next time, but got the same results.

这里的code设立在viewDidLoad中的OpenAL的声音(改编自的本教程):

Here's the code for setting up the OpenAL sound in viewDidLoad (adapted from this tutorial):

// set up the context and device
ALCcontext *context;
ALCdevice *device;
OSStatus result;
device = alcOpenDevice(NULL); // select the "preferred device"
if (device) {
    context = alcCreateContext(device, NULL); // use the device to make a context
    alcMakeContextCurrent(context); // set the context to the currently active one
}

// open the sound file
NSString *soundFilePath = [[NSBundle mainBundle] pathForResource:@"TempoClick" ofType:@"caf"];
NSURL *soundFileURL = [NSURL fileURLWithPath:soundFilePath];
AudioFileID fileID;
result = AudioFileOpenURL((CFURLRef)soundFileURL, kAudioFileReadPermission, 0, &fileID);
if (result != 0) DLog(@"cannot open file %@: %ld", soundFilePath, result);

// get the size of the file data
UInt32 fileSize = 0;
UInt32 propSize = sizeof(UInt64);
result = AudioFileGetProperty(fileID, kAudioFilePropertyAudioDataByteCount, &propSize, &fileSize);
if (result != 0) DLog(@"cannot find file size: %ld", result);
DLog(@"file size: %li", fileSize);

// copy the data into a buffer, then close the file
unsigned char *outData = malloc(fileSize);
AudioFileOpenURL((CFURLRef)soundFileURL, kAudioFileReadPermission, 0, &fileID); // we get a "file is not open" error on the next line if we don't open this again
result = AudioFileReadBytes(fileID, false, 0, &fileSize, outData);
if (result != 0) NSLog(@"cannot load data: %ld", result);
AudioFileClose(fileID);
alGenBuffers(1, &tempoSoundBuffer);
alBufferData(self.tempoSoundBuffer, AL_FORMAT_MONO16, outData, fileSize, 44100);
free(outData);
outData = NULL;

// connect the buffer to the source and set some preferences
alGenSources(1, &tempoSoundSource); 
alSourcei(tempoSoundSource, AL_BUFFER, tempoSoundBuffer);
alSourcef(tempoSoundSource, AL_PITCH, 1.0f);
alSourcef(tempoSoundSource, AL_GAIN, 1.0f);
alSourcei(tempoSoundSource, AL_LOOPING, AL_FALSE);

和则在剧中方法我只要致电:

And then in the play method I just call:

alSourcePlay(self.tempoSoundSource);

谁能解释一下是怎么回事,我该怎么解决呢?

Can anyone explain what is happening here, and how I can work around it?

更新1:

我有另一个项目,播放音频单元简短的声音,从而快速测试我添加了一个定时器,该项目发挥出自己的咔嚓声每隔400毫秒。在这种情况下,定时几乎是完美的。因此,似乎是的NSTimer不错,但系统声音,AVAudioPlayer和OpenAL的是在他们播放的音频比单位不准确。

I have another project that plays brief sounds with audio units, so as a quick test I added a timer to that project to play my click sound every 400 milliseconds. In that case, the timing is nearly perfect. So, it seems that NSTimer is fine but system sounds, AVAudioPlayer and OpenAL are less accurate in their playback than audio units.

更新2:

我刚刚重新设计我的项目使用的音频单元,现在音频更准确地回放了。它仍偶尔漂移通过向任意方向上的四个毫秒,但是这是比其他音频的方法更好。我仍然好奇,为什么其他方法都显示短,短,短,长间隔的模式 - 它像音频播放时间被四舍五入向上或向下映射到某种帧速率 - 所以我会离开这个问题公开的人谁能够解释和/或提供其它音频方法解决方法。

I just reworked my project to use audio units and now the audio is playing back much more accurately. It still occasionally drifts by up to four milliseconds in either direction, but this is better than the other audio methods. I'm still curious why the other methods all show a pattern of short, short, short, long intervals -- it's like the audio playback times are being rounded up or down to map to some kind of frame rate -- so I'll leave this question open for anyone who can explain that and/or offer a workaround for the other audio methods.

推荐答案

好吧,我已经想通了。真正的原因音频单位工作过,比其他音频方法更好的是,我的音频单元类,我是从另一个项目调整,在音频会议设置一个缓冲时间属性,如:

Okay, I've figured it out. The real reason audio units worked better than the other audio methods is that my audio unit class, which I was adapting from another project, was setting a buffer duration property in the audio session, like this:

Float32 preferredBufferSize = .001;
UInt32 size = sizeof(preferredBufferSize);
AudioSessionSetProperty(kAudioSessionProperty_PreferredHardwareIOBufferDuration, size, &preferredBufferSize);

当我加入这个code到OpenAL的版本,甚至到AVAudioPlayer版本,我得到了精度在几毫秒内,同为音频单元。 (系统声音,但仍然不是很准确)。我可以验证通过增加缓冲区的大小和观看回放间隔得到不准确的连接。

When I added this code to the OpenAL version, or even to the AVAudioPlayer version, I got accuracy to within a few milliseconds, the same as with audio units. (System Sounds, however, were still not very accurate.) I can verify the connection by increasing the buffer size and watching the playback intervals get less accurate.

当然,我只花一整天的时间适应我的项目使用的音频单元后想通了这一点。

Of course I only figured this out after spending an entire day adapting my project to use audio units -- tweaking it to compile under C++, testing the interruption handlers, etc. I hope this can save someone else from the same trouble.

这篇关于为什么我的声音听起来不玩的时间?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆