Воспроизведение аудио файла.caf с ExtAudioFileRead не синхронизировано

Мое приложение выполняет огромную обработку данных на аудио, поступающем с микрофонного входа. Чтобы получить "демонстрационный режим", я хочу сделать то же самое на основе локального аудиофайла.caf. Мне удалось получить аудиофайл. Теперь я пытаюсь использовать ExtAudioFileRead, чтобы прочитать файл.caf, а затем выполнить обработку данных.

void readFile()
{
OSStatus err = noErr;

// Audio file
NSURL *path = [[NSBundle mainBundle] URLForResource:@"output" withExtension:@"caf"];
ExtAudioFileOpenURL((__bridge CFURLRef)path, &audio->audiofile);
assert(audio->audiofile);

// File's format.
AudioStreamBasicDescription fileFormat;
UInt32 size = sizeof(fileFormat);
err = ExtAudioFileGetProperty(audio->audiofile, kExtAudioFileProperty_FileDataFormat, &size, &fileFormat);

// tell the ExtAudioFile API what format we want samples back in
//bzero(&audio->clientFormat, sizeof(audio->clientFormat));
audio->clientFormat.mSampleRate         = SampleRate;
audio->clientFormat.mFormatID           = kAudioFormatLinearPCM;
audio->clientFormat.mFormatFlags        = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked;
audio->clientFormat.mFramesPerPacket    = 1;
audio->clientFormat.mChannelsPerFrame   = 1;
audio->clientFormat.mBitsPerChannel     = 16;//sizeof(AudioSampleType) * 8;
audio->clientFormat.mBytesPerPacket     = 2 * audio->clientFormat.mChannelsPerFrame;
audio->clientFormat.mBytesPerFrame      = 2 * audio->clientFormat.mChannelsPerFrame;
err = ExtAudioFileSetProperty(audio->audiofile, kExtAudioFileProperty_ClientDataFormat, sizeof(audio->clientFormat), &audio->clientFormat);

// find out how many frames we need to read
SInt64 numFrames = 0;
size = sizeof(numFrames);
err = ExtAudioFileGetProperty(audio->audiofile, kExtAudioFileProperty_FileLengthFrames, &size, &numFrames);

// create the buffers for reading in data
AudioBufferList *bufferList = malloc(sizeof(AudioBufferList) + sizeof(AudioBuffer) * (audio->clientFormat.mChannelsPerFrame - 1));
bufferList->mNumberBuffers = audio->clientFormat.mChannelsPerFrame;
for (int ii=0; ii < bufferList->mNumberBuffers; ++ii)
{
    bufferList->mBuffers[ii].mDataByteSize = sizeof(float) * (int)numFrames;
    bufferList->mBuffers[ii].mNumberChannels = 1;
    bufferList->mBuffers[ii].mData = malloc(bufferList->mBuffers[ii].mDataByteSize);
}

UInt32 maxReadFrames = 1024;
UInt32 rFrames = (UInt32)numFrames;
while(rFrames > 0)
{
    UInt32 framesToRead = (maxReadFrames > rFrames) ? rFrames : maxReadFrames;
    err = ExtAudioFileRead(audio->audiofile, &framesToRead, bufferList);
    [audio processAudio:bufferList];
    if (rFrames % SampleRate == 0)
        [audio realtimeUpdate:nil];
    rFrames = rFrames - maxReadFrames;
}

// Close the file
ExtAudioFileDispose(audio->audiofile);

// destroy the buffers
for (int ii=0; ii < bufferList->mNumberBuffers; ++ii)
{
    free(bufferList->mBuffers[ii].mData);
}
free(bufferList);
bufferList = NULL;
}

Ясно, что я что-то не понял или что-то не так с ExtAudioFileRead, потому что этот код не работает вообще. У меня есть две основные проблемы:

  1. Файл воспроизводится мгновенно. Я имею в виду, что 44'100 образцов явно не равны 1 секунде. Моя обработка аудио файла за 3 минуты выполняется за несколько секунд...
  2. Во время обработки мне нужно обновить интерфейс. Так что у меня есть несколько dispatch_sync в processaudio а также realtimeUpdate, Похоже, что ExtAudioFileRead действительно не ценит это, и он зависает. Спасибо за помощь.

1 ответ

Код, который вы написали, просто читает примеры из файла и затем вызывает processAudio. Это будет сделано как можно быстрее. Как только процесс processAudio завершен, читается следующая партия образцов и снова вызывается processAudio. Не следует предполагать, что чтение из аудиофайла (который является низкоуровневым и неблокирующим вызовом os) занимает то же время, что и чтение аудио, которое потребуется для воспроизведения. Если вы хотите обработать звук в файле в соответствии с частотой дискретизации, вам, вероятно, следует использовать аудиоустройство AUFilePlayer. Это может воспроизвести файл с правильной скоростью, и вы можете использовать обратный вызов для обработки семплов в реальном времени, а не "как можно быстрее".

Другие вопросы по тегам