4

Вопрос по ios – Запись из RemoteIO: результирующий .caf смещен по высоте более медленно + искажен

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

Моя настройка: у меня есть существующий AUGraph: (несколько AUSamplers -> Mixer -> RemoteIO). AUSamplers связаны с дорожками в экземпляре MusicPlayer. Это все работает нормально, но Я хочу добавить запись к нему.

Запись работает, но результирующий .caf медленнее сдвигается по высоте / темпу + имеет плохое качество звука. Должно быть что-то не так с форматом, который я указываю?

Может кто-то посмотрит на это и скажет, где я неправильно устанавливаю формат?

EDIT: это может быть проблема стерео / моно? Я имею в виду запись в моно.

Я установил формат потока на экземпляре RemoteIO следующим образом:

   AudioStreamBasicDescription audioFormat;

audioFormat.mSampleRate         = 44100.00;
audioFormat.mFormatID           = kAudioFormatLinearPCM;
audioFormat.mFormatFlags        = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked;
audioFormat.mFramesPerPacket    = 1;
audioFormat.mChannelsPerFrame   = 1;
audioFormat.mBitsPerChannel     = 16;
audioFormat.mBytesPerPacket     = 2;
audioFormat.mBytesPerFrame      = 2;

// Apply format
result = AudioUnitSetProperty(ioUnit, 
                              kAudioUnitProperty_StreamFormat, 
                              kAudioUnitScope_Output, 
                              kInputBus, 
                              &audioFormat, 
                              sizeof(audioFormat));

Затем из действия кнопки я создаю fileRef и присоединяю renderCallback к экземпляру RemoteIO:

- (void)startRecording
{

OSStatus result;

AudioStreamBasicDescription audioFormat;

audioFormat.mSampleRate         = 44100.00;
audioFormat.mFormatID           = kAudioFormatLinearPCM;
audioFormat.mFormatFlags        = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked;
audioFormat.mFramesPerPacket    = 1;
audioFormat.mChannelsPerFrame   = 1;
audioFormat.mBitsPerChannel     = 16;
audioFormat.mBytesPerPacket     = 2;
audioFormat.mBytesPerFrame      = 2;

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

result = ExtAudioFileCreateWithURL(destinationURL, 
                                   kAudioFileWAVEType, 
                                   &audioFormat, 
                                   NULL, 
                                   kAudioFileFlags_EraseFile, 
                                   &extAudioFileRef);  

CFRelease(destinationURL);
NSAssert(result == noErr, @"Couldn't create file for writing");

result = ExtAudioFileSetProperty(extAudioFileRef, 
                                 kExtAudioFileProperty_ClientDataFormat, 
                                 sizeof(AudioStreamBasicDescription), 
                                 &audioFormat);

NSAssert(result == noErr, @"Couldn't create file for format");

result =  ExtAudioFileWriteAsync(extAudioFileRef, 0, NULL);
NSAssert(result == noErr, @"Couldn't initialize write buffers for audio file");   


printf("Adding render to remoteIO     \n");
result = AudioUnitAddRenderNotify(ioUnit, renderCallback, (__bridge void*)self);
if (result) {[self printErrorMessage: @"AudioUnitAddRenderNotify" withStatus: result]; return;}
 }

Наконец, в моем обратном вызове рендера я записываю данные на этапе postRender:

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

OSStatus result;
   if (*ioActionFlags == kAudioUnitRenderAction_PostRender){
    double timeInSeconds = inTimeStamp->mSampleTime / kSampleRate;
    printf("%fs inBusNumber: %lu inNumberFrames: %lu \n", timeInSeconds, inBusNumber, inNumberFrames);

    MusicPlayerController* THIS = (__bridge MusicPlayerController *)inRefCon;

   result =  ExtAudioFileWriteAsync(THIS->extAudioFileRef, inNumberFrames, ioData);
    if(result) printf("ExtAudioFileWriteAsync %ld \n", result);

  }

return noErr; 
}
  • Error: User Rate Limit Exceeded

    от
  • Error: User Rate Limit Exceeded

    от
  • Error: User Rate Limit Exceeded

    от No Grabbing
  • Error: User Rate Limit Exceeded

    от
  • Здравствуйте, я понял, что вы пишете в файл в renderCallback, а я делаю это в обратном вызове уведомлений рендеринга, настроенном с помощью AUGraphAddRenderNotify. Я не получаю EXC_BAD_ACCESS, если я создаю копию ioData. Я дам вам знать, в чем проблема, когда я это исправлю. Большое спасибо!

    от Martin Konicek
  • @MartinKonicek - у меня не было проблем с аварийным завершением работы с ExtAudioFileWriteAsync. Может быть, что-то выходит, чего не должно быть?

    от No Grabbing
  • Работает ли у вас вызов ExtAudioFileWriteAsync из renderCallback? Для меня это почему-то завершается с AURemoteIO :: IOThread EXC_BAD_ACCESS. renderCallback работает в фоновом потоке, не так ли?

    от Martin Konicek
  • 3

    Хорошо - нашел какой-то код

    который решает эту проблему - хотя я не совсем понимаю, почему.

    Я устанавливалmBitsPerChannel до 16 для выходного потока RemoteIO и ExtFileRef. Результат был замедлен & amp; скрипучий звук. Установка ExtFileRefmBitsPerChannel до 32 плюс добавлениеkAudioFormatFlagsNativeEndian Флаг решает проблему: аудио .caf идеально (оставляя настройки потока вывода RemoteIO на прежнем уровне).

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

    Во всяком случае ... рабочая настройка ниже.

    size_t bytesPerSample = sizeof (AudioUnitSampleType);
    
    AudioStreamBasicDescription audioFormat;
    audioFormat.mSampleRate= graphSampleRate;
    audioFormat.mFormatID=kAudioFormatLinearPCM;
    audioFormat.mFormatFlags=kAudioFormatFlagsNativeEndian|kAudioFormatFlagIsSignedInteger|kAudioFormatFlagIsPacked;
    audioFormat.mBytesPerPacket=bytesPerSample;
    audioFormat.mBytesPerFrame=bytesPerSample;
    audioFormat.mFramesPerPacket=1;
    audioFormat.mChannelsPerFrame=1;
    audioFormat.mBitsPerChannel= 8 * bytesPerSample;
    audioFormat.mReserved=0;