Escribir audio a disco desde la unidad IO

Reescribir esta pregunta para ser un poco más sucinta.

Mi problema es que no puedo escribir correctamente un file de audio en el disco desde una unidad IO remota.

Los pasos que tomé fueron

Abra un file mp3 y extraiga su audio a los búferes. Configuré un asbd para usar con mi gráfico en function de las properties del gráfico. ¡Configuro y ejecuto mi gráfico haciendo que el audio y el sonido extraídos salgan exitosamente del altavoz!

Lo que estoy teniendo dificultades es tomar las muestras de audio de la callback IO remota y escribirlas en un file de audio en el disco para el que estoy usando ExtAudioFileWriteASync.

El file de audio se escribe y tiene cierta semejanza audible con el mp3 original, pero suena muy distorsionado.

No estoy seguro si el problema es

A) ExtAudioFileWriteAsync no puede escribir las muestras tan rápido como les proporciona la callback de la unidad io.

  • o –

B) He configurado el ASBD para la reference extaudiofile incorrecta. Quería comenzar guardando un file wav. No estoy seguro si describí esto correctamente en el ASBD a continuación.

En segundo lugar, no estoy seguro de qué valor pasar para la propiedad inChannelLayout al crear el file de audio.

Y, finalmente, estoy muy inseguro sobre qué asbd para usar para kExtAudioFileProperty_ClientDataFormat. Había estado usando mi formatting de transmisión estéreo, pero una mirada más cercana a los documentos dice que esto debe ser pcm. ¿Debería ser el mismo formatting que la salida para el remoteio? ¿Y si fuera así, me equivoque al configurar el formatting de salida del io remoto en stereostreamformat?

Me doy count de que hay mucho y mucho en esta pregunta, pero tengo muchas incertidumbres que no puedo aclarar por mi count.

configurar el formatting de transmisión estéreo

- (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 :"); } 

configurar la callback remota mediante el formatting de transmisión estéreo

 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; } 

** la configuration de grabación **

 -(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's 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]; } 

editar 1

Ahora estoy apuñalándome en la oscuridad, pero ¿necesito usar un convertidor de audio o kExtAudioFileProperty_ClientDataFormat se encarga de eso?

editar 2

Estoy adjuntando 2 muestras de audio. El primero es el audio original que estoy haciendo y tratando de copyr. El segundo es el audio grabado de ese ciclo. Es de esperar que le dé a alguien la key de lo que va mal.

Mp3 original

Grabación de problemas de mp3

Después de un par de días de lágrimas y tirones de cabello, tengo una solución.

En mi código y en otros ejemplos he visto extaudiofilewriteasync se llamó en la callback para la unidad remota como tal.

** llamada remota **

 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; } 

En esta callback, estoy obteniendo datos de audio de otra unidad de audio que aplica ecuaciones y mezclas de audio.

¡Quité la llamada extaudiofilewriteasync de la callback remota a esta otra callback que tira el control remoto y el file escribe con éxito!

* function de callback 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; } 

Con el fin de comprender por qué mi solución funcionó, ¿alguien podría explicarme por qué escribir datos en el file de la list de almacenamiento de datos de iodata del remoteio provoca un audio distorsionado, pero escribir datos un paso más allá de la cadena da como resultado un audio perfecto?