Как записать вывод AUGraph в файл? - PullRequest
5 голосов
/ 21 января 2012

Я пытаюсь написать (что должно быть) простое приложение, которое имеет последовательность аудиоустройств в AUGraph, а затем записывает вывод в файл.Я добавил обратный вызов, используя AUGraphAddRenderNotify.Вот моя функция обратного вызова:

OSStatus MyAURenderCallback(void *inRefCon,
                        AudioUnitRenderActionFlags *actionFlags,
                        const AudioTimeStamp *inTimeStamp,
                        UInt32 inBusNumber,
                        UInt32 inNumberFrames,
                        AudioBufferList *ioData) {
    if (*actionFlags & kAudioUnitRenderAction_PostRender) {
        ExtAudioFileRef outputFile = (ExtAudioFileRef)inRefCon;
        ExtAudioFileWriteAsync(outputFile, inNumberFrames, ioData);
    }
}

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

Кто-нибудь знает, что с этим не так?Или кто-нибудь знает, как лучше записать вывод AUGraph в файл?

Спасибо за помощь.

Ответы [ 3 ]

6 голосов
/ 26 января 2012

У меня было прозрение относительно Аудиоустройств только что, которое помогло мне решить мою собственную проблему.У меня было неправильное представление о том, как работают соединения аудиоустройств и обратные вызовы рендеринга.Я думал, что это были совершенно разные вещи, но оказалось, что соединение - это просто короткая рука для обратного вызова рендеринга.

Выполнение kAudioUnitProperty_MakeConnection с выхода аудиоустройства A на вход аудиоустройства B аналогично выполнению kAudioUnitProperty_SetRenderCallback на входе блока B и вызову функции обратного вызова AudioUnitRender на выходе аудиоустройства A.

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

Поэтому я смог решить свою проблему, выполнив следующие действия:

AURenderCallbackStruct callbackStruct = {0};
callbackStruct.inputProc = MyAURenderCallback;
callbackStruct.inputProcRefCon = mixerUnit;

AudioUnitSetProperty(ioUnit,
                     kAudioUnitProperty_SetRenderCallback,
                     kAudioUnitScope_Input,
                     0,
                     &callbackStruct,
                     sizeof(callbackStruct));

И моя функция обратного вызова сделала что-то вроде этого:

OSStatus MyAURenderCallback(void *inRefCon,
                        AudioUnitRenderActionFlags *actionFlags,
                        const AudioTimeStamp *inTimeStamp,
                        UInt32 inBusNumber,
                        UInt32 inNumberFrames,
                        AudioBufferList *ioData) {

    AudioUnit mixerUnit = (AudioUnit)inRefCon;

    AudioUnitRender(mixerUnit,
                    actionFlags,
                    inTimeStamp,
                    0,
                    inNumberFrames,
                    ioData);

    ExtAudioFileWriteAsync(outputFile, 
                           inNumberFrames, 
                           ioData);

    return noErr;
}

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

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

1 голос
/ 23 января 2012

Вот пример кода от Apple (проект PlaySequence, но он не специфичен для MIDI), который может помочь:

{
    CAStreamBasicDescription clientFormat = CAStreamBasicDescription();
    ca_require_noerr (result = AudioUnitGetProperty(outputUnit,
                                                    kAudioUnitProperty_StreamFormat,
                                                    kAudioUnitScope_Output, 0,
                                                    &clientFormat, &size), fail);
    size = sizeof(clientFormat);
    ca_require_noerr (result = ExtAudioFileSetProperty(outfile, kExtAudioFileProperty_ClientDataFormat, size, &clientFormat), fail);

    {
        MusicTimeStamp currentTime;
        AUOutputBL outputBuffer (clientFormat, numFrames);
        AudioTimeStamp tStamp;
        memset (&tStamp, 0, sizeof(AudioTimeStamp));
        tStamp.mFlags = kAudioTimeStampSampleTimeValid;
        int i = 0;
        int numTimesFor10Secs = (int)(10. / (numFrames / srate));
        do {
            outputBuffer.Prepare();
            AudioUnitRenderActionFlags actionFlags = 0;
            ca_require_noerr (result = AudioUnitRender (outputUnit, &actionFlags, &tStamp, 0, numFrames, outputBuffer.ABL()), fail);

            tStamp.mSampleTime += numFrames;

            ca_require_noerr (result = ExtAudioFileWrite(outfile, numFrames, outputBuffer.ABL()), fail);    

            ca_require_noerr (result = MusicPlayerGetTime (player, &currentTime), fail);
            if (shouldPrint && (++i % numTimesFor10Secs == 0))
                printf ("current time: %6.2f beats\n", currentTime);
        } while (currentTime < sequenceLength);
    }
}
0 голосов
/ 21 января 2012

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

...