Запись аудио на диск из модуля ввода-вывода

Переписывая этот вопрос немного лучше.

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

Я сделал шаги

Откройте mp3 файл и извлеките его аудио в буферы. Я настроил asbd для использования с моим графиком, основанным на свойствах графика. Я настраиваю и запускаю мой цикл графика, извлеченный звук и звук успешно выходят из динамика!

У меня с трудом возникает выборка аудиоданных из удаленного обратного вызова IO и запись их в аудиофайл на диске, который я использую для ExtAudioFileWriteASync для.

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

Я не уверен, что проблема

A) ExtAudioFileWriteAsync не может записывать образцы так же быстро, как и их обратный вызов.

  • или -

B) Я неправильно настроил ASBD для исключения extaudiofile. Я хотел начать с сохранения wav файла. Я не уверен, правильно ли я описал это в ASBD ниже.

Во-вторых, я не уверен, какое значение передать для свойства inChannelLayout при создании аудиофайла.

И, наконец, я очень не уверен в том, что asbd использовать для kExtAudioFileProperty_ClientDataFormat. Я использовал формат стереопотока, но более пристальный взгляд на документы говорит, что это должно быть pcm. Должен ли это быть тот же формат, что и выход для удаленного? И если я ошибался, чтобы установить выходной формат удаленного io в стереотекстовый формат?

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

настройка формата стерео потока

- (void) setupStereoStreamFormat
{

    size_t bytesPerSample = sizeof (AudioUnitSampleType);
    stereoStreamFormat.mFormatID          = kAudioFormatLinearPCM;
    stereoStreamFormat.mFormatFlags       = kAudioFormatFlagsAudioUnitCanonical;
    stereoStreamFormat.mBytesPerPacket    = bytesPerSample;
    stereoStreamFormat.mFramesPerPacket   = 1;
    stereoStreamFormat.mBytesPerFrame     = bytesPerSample;
    stereoStreamFormat.mChannelsPerFrame  = 2;                    // 2 indicates stereo
    stereoStreamFormat.mBitsPerChannel    = 8 * bytesPerSample;
    stereoStreamFormat.mSampleRate        = engineDescribtion.samplerate;

    NSLog (@"The stereo stereo format :");


}

настроить удаленный вызов с использованием формата стерео потока

AudioUnitSetProperty(engineDescribtion.masterChannelMixerUnit, 
                             kAudioUnitProperty_StreamFormat, 
                             kAudioUnitScope_Output, 
                             masterChannelMixerUnitloop, 
                             &stereoStreamFormat, 
                             sizeof(stereoStreamFormat));

        AudioUnitSetProperty(engineDescribtion.masterChannelMixerUnit, 
                             kAudioUnitProperty_StreamFormat, 
                             kAudioUnitScope_Input, 
                             masterChannelMixerUnitloop, 
                             &stereoStreamFormat, 
                             sizeof(stereoStreamFormat));




static OSStatus masterChannelMixerUnitCallback(void *inRefCon, 
                              AudioUnitRenderActionFlags *ioActionFlags, 
                              const AudioTimeStamp *inTimeStamp, 
                              UInt32 inBusNumber, 
                              UInt32 inNumberFrames, 
                              AudioBufferList *ioData)

{

   // ref.equnit;
    //AudioUnitRender(engineDescribtion.channelMixers[inBusNumber], ioActionFlags, inTimeStamp, 0, inNumberFrames, ioData);
    Engine *engine= (Engine *) inRefCon;
    AudioUnitRender(engineDescribtion.equnit, ioActionFlags, inTimeStamp, 0, inNumberFrames, ioData);

    if(engine->isrecording)
    {
        ExtAudioFileWriteAsync(engine->recordingfileref, inNumberFrames, ioData);

    }


    return 0;

}

** установка записи **

-(void)startrecording

{

    NSArray  *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentsDirectory = [paths objectAtIndex:0];
    destinationFilePath = [[NSString alloc] initWithFormat: @"%@/testrecording.wav", documentsDirectory];
    destinationURL = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, (CFStringRef)destinationFilePath, kCFURLPOSIXPathStyle, false);

    OSStatus status;

    // prepare a 16-bit int file format, sample channel count and sample rate
    AudioStreamBasicDescription dstFormat;
    dstFormat.mSampleRate=44100.0;
    dstFormat.mFormatID=kAudioFormatLinearPCM;
    dstFormat.mFormatFlags=kAudioFormatFlagsNativeEndian|kAudioFormatFlagIsSignedInteger|kAudioFormatFlagIsPacked;
    dstFormat.mBytesPerPacket=4;
    dstFormat.mBytesPerFrame=4;
    dstFormat.mFramesPerPacket=1;
    dstFormat.mChannelsPerFrame=2;
    dstFormat.mBitsPerChannel=16;
    dstFormat.mReserved=0;

    // create the capture file
  status=  ExtAudioFileCreateWithURL(destinationURL, kAudioFileWAVEType, &dstFormat, NULL, kAudioFileFlags_EraseFile, &recordingfileref);
    CheckError( status ,"couldnt create audio file");
        // set the capture file client format to be the canonical format from the queue
 status=ExtAudioFileSetProperty(recordingfileref, kExtAudioFileProperty_ClientDataFormat, sizeof(AudioStreamBasicDescription), &stereoStreamFormat);

    CheckError( status ,"couldnt set input format");

    ExtAudioFileSeek(recordingfileref, 0);
 isrecording=YES;

  // [documentsDirectory release];


}

изменить 1

Я сейчас нахожусь в темноте здесь, но мне нужно использовать аудиоконвертер, или kExtAudioFileProperty_ClientDataFormat позаботится об этом?

изменить 2

Im прикрепляет 2 образца аудио. Первый - это оригинальный звук, который Im зацикливает и пытается скопировать. Второй - записанный звук этого цикла. Надеюсь, это может дать кому-то понять, что происходит не так.

Оригинальный mp3

Проблема записи mp3

Ответ 1

После нескольких дней слез и вытягивания волос у меня есть решение.

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

** удаленный вызов **

static OSStatus masterChannelMixerUnitCallback(void *inRefCon, 
                              AudioUnitRenderActionFlags *ioActionFlags, 
                              const AudioTimeStamp *inTimeStamp, 
                              UInt32 inBusNumber, 
                              UInt32 inNumberFrames, 
                              AudioBufferList *ioData)

{


    AudioUnitRender(engineDescribtion.equnit, ioActionFlags, inTimeStamp, 0, inNumberFrames, ioData);


    if(isrecording)
    {
        ExtAudioFileWriteAsync(engine->recordingfileref, inNumberFrames, ioData);


    }



    return 0;

}

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

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

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

static OSStatus outputCallback(void *inRefCon, 
                               AudioUnitRenderActionFlags *ioActionFlags, 
                               const AudioTimeStamp *inTimeStamp, 
                               UInt32 inBusNumber, 
                               UInt32 inNumberFrames, 
                               AudioBufferList *ioData) {  


    AudioUnitRender(engineDescribtion.masterChannelMixerUnit, ioActionFlags, inTimeStamp, 0, inNumberFrames, ioData);

   //process audio here    

    Engine *engine= (Engine *) inRefCon;


    OSStatus s;

    if(engine->isrecording)
    {
        s=ExtAudioFileWriteAsync(engine->recordingfileref, inNumberFrames, ioData);


    }


    return noErr;

}

В интересах полного понимания того, почему мое решение сработало, может кто-нибудь объяснить мне, почему запись данных в файл из iodata-буфера списка удаленных приложений вызывает искаженное аудио, но запись данных еще один шаг вниз по цепочке приводит к идеальному аудио?