내 앱 중 하나에는 분당 지정된 횟수 (bpm)의 클릭 사운드를 재생하는 간단한 메트로놈 스타일 기능이 있습니다. 나는 소리를 재생하는 메서드를 호출하는 지정된 bpm에서 계산 된 간격으로 NSTimer를 시작하여이 작업을 수행합니다.오디오 사운드가 제 시간에 재생되지 않는 이유는 무엇입니까?
NSLog 라인을 재생 방법에 넣으면 NSTimer가 약 1 밀리 초까지 정확하게 실행된다는 것을 알 수 있습니다. 그러나 사운드 출력을 오디오 편집기에 기록한 다음 클릭 간격을 측정하면 균등하지는 않습니다. 예를 들어, 150 bpm의 경우 타이머는 400 밀리 초마다 실행됩니다. 그러나 대부분의 사운드는 395 밀리 초 후에 재생되며, 3 번째 또는 4 번째 사운드는 418 밀리 초 후에 재생됩니다.
그래서 소리가 일정하게 지연되지는 않지만 오히려 더 짧고 긴 간격의 패턴을 따릅니다. iOS의 사운드 타이밍이 더 낮아진 것처럼 보이며 각 사운드 이벤트를 가장 가까운 사용 가능 지점으로 반올림하여 필요에 따라 반올림하여 전반적인 트랙을 유지합니다.
나는 이것을 시스템 사운드, AVAudioPlayer 및 OpenAL과 함께 시도했으며 세 가지 방법 모두에서 똑같은 결과를 얻었습니다. 각 메서드를 사용하면 뷰가로드 될 때 모든 설정을 수행하므로 사운드를 재생할 때마다 반드시 재생해야합니다. AVAudioPlayer를 사용하여 사운드가 재생 될 때마다 두 번째 타이머를 사용하여 prepareToPlay를 호출 했으므로 다음 시간에 초기화 할 준비가되었지만 동일한 결과가 나타납니다.
// 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);
그리고 재생 방법에 난 그냥 전화 :
이alSourcePlay(self.tempoSoundSource);
사람이 무엇을 설명 할 수 여기에
은 ( this tutorial에서 적응)의 viewDidLoad에서 OpenAL에 사운드를 설정하기위한 코드입니다 여기서 일어나는 일, 어떻게 해결할 수 있을까요?UPDATE 1 :
나는이 내 클릭 소리마다 400 밀리 초를 재생하는 프로젝트에 타이머를 추가 빠른 테스트 있도록, 오디오 장치와 짧은 소리를 재생 다른 프로젝트. 이 경우 타이밍은 거의 완벽합니다. 따라서 NSTimer는 괜찮지 만 시스템 사운드는 AVAudioPlayer와 OpenAL이 오디오 단위보다 재생이 덜 정확합니다.
UPDATE 2 :
난 그냥 오디오 장치를 사용하는 내 프로젝트를 재 이제 오디오는 더 정확하게 다시 많이 연주된다. 어느 방향 으로든 가끔씩 최대 4 밀리 초씩 변동하는 경우가 있지만 다른 오디오 방법보다 좋습니다. 다른 방법들이 모두 짧고 짧고 짧고 긴 간격의 패턴을 보여주는 이유는 여전히 궁금합니다. 오디오 재생 시간을 반올림하여 프레임 속도에 매핑하는 것과 같습니다. 설명 할 수있는 사람이나 다른 오디오 방법에 대한 해결책을 제공 할 수있는 사람들에게이 질문을 공개하십시오.
확실하지 않지만 NSLog가 지연을 초래할 수도 있습니다. – Ahmed
@Ahmed : 좋은 생각인데 NSLog를 주석 처리하고 같은 결과를 얻었습니다. – arlomedia
가능한 [아이폰에 실시간 정확한 오디오 시퀀서를 프로그래밍하는 방법?] (http://stackoverflow.com/questions/907137/how-to-program-a-real-time-accurate-audio-sequencer) -on-the-iphone) – benzado