2016-06-07 3 views
2

Просто не может быть очень далеко в Core Audio. Моя цель - записать записанные аудиоданные с инструментального блока в файл. Я настроил вызов функции обратного вызова на блоке приборов с этим:Использование функции ExtAudioFileWriteAsync() в функции обратного вызова. Не удается запустить

CheckError(AudioUnitAddRenderNotify(player->instrumentUnit, 
            MyRenderProc, 
            &player), 
      "AudioUnitAddRenderNotify Failed"); 

Я создал файл и AudioStreamBasicDescription с этим:

#define FILENAME @"output_IV.aif" 

NSString *fileName = FILENAME; // [NSString stringWithFormat:FILENAME_FORMAT, hz]; 
NSString *filePath = [[[NSFileManager defaultManager] currentDirectoryPath] stringByAppendingPathComponent: fileName]; 
NSURL *fileURL = [NSURL fileURLWithPath: filePath]; 
NSLog (@"path: %@", fileURL); 

AudioStreamBasicDescription asbd; 
memset(&asbd, 0, sizeof(asbd)); 
asbd.mSampleRate = 44100.0; 
asbd.mFormatID = kAudioFormatLinearPCM; 
asbd.mFormatFlags = kAudioFormatFlagIsBigEndian | kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked; 
asbd.mChannelsPerFrame = 2; // CHANGED FROM 1 (STEREO) 
asbd.mFramesPerPacket = 1; 
asbd.mBitsPerChannel = 16; 
asbd.mBytesPerFrame = 4; 
asbd.mBytesPerPacket = 4; 

CheckError(ExtAudioFileCreateWithURL((__bridge CFURLRef)fileURL, kAudioFileAIFFType, &asbd, NULL, kAudioFileFlags_EraseFile, &testRecordFile), "ExtAudioFileCreateWithURL failed"); 
CheckError(ExtAudioFileSetProperty(testRecordFile, kExtAudioFileProperty_ClientDataFormat, (UInt32)sizeof(asbd), &asbd), "ExtAudioFileSetProperty failed"); 
CheckError(ExtAudioFileWriteAsync(testRecordFile, 0, NULL), "ExtAudioFileWriteAsync 1st time failed"); 

Я проверить, что файл не получить создан. testRecordFile определена глобально (это единственный способ, которым я мог бы получить вещи, чтобы работать в данный момент):

ExtAudioFileRef testRecordFile; 

Моя функция обратного вызова:

OSStatus MyRenderProc(void *inRefCon, 
        AudioUnitRenderActionFlags *ioActionFlags, 
        const AudioTimeStamp *inTimeStamp, 
        UInt32 inBusNumber, 
        UInt32 inNumberFrames, 
        AudioBufferList * ioData) 
{ 
    if (*ioActionFlags & kAudioUnitRenderAction_PostRender){ 
    static int TEMP_kAudioUnitRenderAction_PostRenderError = (1 << 8); 
     if (!(*ioActionFlags & TEMP_kAudioUnitRenderAction_PostRenderError)){ 
      CheckError(ExtAudioFileWriteAsync(testRecordFile, inNumberFrames, ioData), "ExtAudioFileWriteAsync failed"); 
     } 
    } 
return noErr; 
} 

Когда я запускаю это программные завихрения и переходит в отладчик mode (lldb) в вызове ExtAudioFileWriteAsync. inNumberFrames = 512, и я подтвердил, что получаю стереоканалы аудиофайлов Float32 в ioData.

Что мне здесь не хватает?

ответ

2

Во-первых, ваш код по-прежнему немного сложный и включает некоторые из «темных углов» CoreAudio и Obj-C. Это более безопасная ставка, прежде всего, чтобы убедиться, что все работает так, как предполагалось, в простой-C, в потоке реального времени. Как только вы отлаживаете эту часть кода, вы можете легко добавить как можно больше Obj-C элегантности.

Игнорирование возможные проблемы преобразования порядка байтов и формат файла для простоты, есть еще один вопрос вы должны либо разрешить автоматически, с помощью утилиты API, или «вручную»:

AFAIK, формат данных для ExtAudioFileWriteAsync() сусле чередоваться, в то время как формат потока для вашего AUGraph равен не. Предполагая, что мы не имеем дело с endiannes и преобразованием формата здесь, так вы можете исправить его вручную (одноканальный пример). В случае, если ваш asbd формат поток не является чередование стерео, вы чередовать данные в буфере, как это: LRLRLRLRLR ...

OSStatus MyRenderProc(void *inRefCon, 
        AudioUnitRenderActionFlags *ioActionFlags, 
        const AudioTimeStamp *inTimeStamp, 
        UInt32 inBusNumber, 
        UInt32 inNumberFrames, 
        AudioBufferList * ioData) 
{ 
AudioBufferList bufferList; 
Float32 samples[inNumberFrames+inNumberFrames]; 

bufferList.mNumberBuffers = 1; 
bufferList.mBuffers[0].mData = samples; 
bufferList.mBuffers[0].mNumberChannels = 1; 
bufferList.mBuffers[0].mDataByteSize = (inNumberFrames+inNumberFrames)*sizeof(Float32); 
Float32 *data = (Float32 *)ioData->mBuffers[0].mData; 

if (*ioActionFlags & kAudioUnitRenderAction_PostRender){ 
    static int TEMP_kAudioUnitRenderAction_PostRenderError = (1 << 8); 
    if (!(*ioActionFlags & TEMP_kAudioUnitRenderAction_PostRenderError) { 
     for(UInt32 i = 0; i < inNumberFrames; i++) 
      samples[i+i] = samples [i+i+1] = data[i];//copy buffer[0] to L & R    
     ExtAudioFileWriteAsync(testRecordFile, inNumberFrames, &bufferList); 
    } 
} 
return noErr; 
} 

Это только один пример, чтобы показать, как это работает. Изучая asbd.mFormatFlags и установив надлежащий формат:

ExtAudioFileSetProperty(testRecordFile, 
         kExtAudioFileProperty_ClientDataFormat, 
         s, 
         &asbd); 

вы можете достичь его более элегантно, но это выходит за рамки вам, что это пост на сегодняшний день.

+0

Это имеет смысл. Я взял приманку в матче между ioData в шаблоне обратного вызова и ExtAudioFileWriteAsync. Мой код будет более обширным, поскольку я пишу в .aif, но у меня есть идея. Благодаря! –

+0

Я проанализировал ваш код - в этом примере я использую CAF вместо AIF, потому что я хотел, чтобы этот пример был ясным и полезным для всех. Apple немного поработала со стандартом AIFF на машинах Intel, объявив линейную версию AIFF с линейным PCM-версией AIFF в качестве подтипа дополнений byte-swapped для добавления AIFC (aka SOWT) и еще более озадачивая формат, объединив стандарты AIFF и AIFC в "AIF". Береги себя. – user3078414

+0

Это сработало! Еще раз спасибо.Надеюсь, когда-нибудь я смогу вернуть карму кому-то, когда я буду более опытным во всем этом. Для будущей ссылки я буду включать рабочий код для AIF ниже. Ура! –

1

Вот рабочий обратный вызов для 16-битного линейного обратного порядка файла стерео AIF:

OSStatus MyRenderProc(void *inRefCon, 
        AudioUnitRenderActionFlags *ioActionFlags, 
        const AudioTimeStamp *inTimeStamp, 
        UInt32 inBusNumber, 
        UInt32 inNumberFrames, 
        AudioBufferList * ioData) 
{ 
    SInt16 samples[inNumberFrames + inNumberFrames]; 
    AudioBufferList bufferList; 
    bufferList.mNumberBuffers = 1; 
    bufferList.mBuffers[0].mData = samples; 
    bufferList.mBuffers[0].mNumberChannels = 1; 
    bufferList.mBuffers[0].mDataByteSize = (inNumberFrames + inNumberFrames) * sizeof(SInt16); 

    Float32 *leftData = (Float32 *)ioData->mBuffers[0].mData; 
    Float32 *rightData = (Float32 *)ioData->mBuffers[1].mData; 

    if (*ioActionFlags & kAudioUnitRenderAction_PostRender){ 
     static int TEMP_kAudioUnitRenderAction_PostRenderError = (1 << 8); 
     if (!(*ioActionFlags & TEMP_kAudioUnitRenderAction_PostRenderError)){ 
      for (UInt32 i = 0; i < inNumberFrames; i++) { 
       samples[i + i] = CFSwapInt16HostToBig((SInt16) SHRT_MAX * (leftData)[i]); 
       samples[i + i + 1] = CFSwapInt16HostToBig((SInt16) SHRT_MAX * (rightData)[i]); 
      } 
     CheckError(ExtAudioFileWriteAsync(testRecordFile, inNumberFrames, &bufferList), "ExtAudioFileWriteAsync failed"); 
     } 
    } 
    return noErr; 
} 
Смежные вопросы