sound play framework swift audio avfoundation

play - Conversión de archivo.m4a a.aiff utilizando AudioConverter Swift



avfoundation swift 4 (1)

Estoy tratando de convertir un archivo de audio dado en formato .m4a a formato .aiff, usando la respuesta de esta publicación . He convertido el código a Swift 3.0.

func convertAudio(_ url: URL, outputURL: URL) { var error : OSStatus = noErr var destinationFile : ExtAudioFileRef? = nil var sourceFile : ExtAudioFileRef? = nil var srcFormat : AudioStreamBasicDescription = AudioStreamBasicDescription() var dstFormat : AudioStreamBasicDescription = AudioStreamBasicDescription() var audioConverter : AudioConverterRef? = nil ExtAudioFileOpenURL(url as CFURL, &sourceFile) var thePropertySize: UInt32 = UInt32(MemoryLayout.stride(ofValue: srcFormat)) ExtAudioFileGetProperty(sourceFile!, kExtAudioFileProperty_FileDataFormat, &thePropertySize, &srcFormat) dstFormat.mSampleRate = 44100 //Set sample rate dstFormat.mFormatID = kAudioFormatLinearPCM dstFormat.mChannelsPerFrame = 1 dstFormat.mBitsPerChannel = 16 dstFormat.mBytesPerPacket = 2 * dstFormat.mChannelsPerFrame dstFormat.mBytesPerFrame = 2 * dstFormat.mChannelsPerFrame dstFormat.mFramesPerPacket = 1 dstFormat.mFormatFlags = kAudioFormatFlagIsBigEndian | kAudioFormatFlagIsSignedInteger //Create destination file ExtAudioFileCreateWithURL(outputURL as CFURL, kAudioFileAIFFType, &dstFormat, nil, AudioFileFlags.eraseFile.rawValue, &destinationFile) ExtAudioFileSetProperty(sourceFile!, kExtAudioFileProperty_ClientDataFormat, thePropertySize, &dstFormat) ExtAudioFileSetProperty(destinationFile!, kExtAudioFileProperty_ClientDataFormat, thePropertySize, &dstFormat) var size : UInt32 = UInt32(MemoryLayout.stride(ofValue: audioConverter)) ExtAudioFileGetProperty(destinationFile!, kExtAudioFileProperty_AudioConverter, &size, &audioConverter) var canResume : UInt32 = 0 size = UInt32(MemoryLayout.stride(ofValue: canResume)) error = AudioConverterGetProperty(audioConverter!, kAudioConverterPropertyCanResumeFromInterruption, &size, &canResume) let bufferByteSize : UInt32 = 32768 var srcBuffer = [UInt8](repeating: 0, count: 32768) var sourceFrameOffset : ULONG = 0 print("Converting audio file") while(true){ var fillBufList = AudioBufferList( mNumberBuffers: 1, mBuffers: AudioBuffer( mNumberChannels: 2, mDataByteSize: UInt32(srcBuffer.count), mData: &srcBuffer ) ) var numFrames : UInt32 = 0 if(dstFormat.mBytesPerFrame > 0){ numFrames = bufferByteSize / dstFormat.mBytesPerFrame } ExtAudioFileRead(sourceFile!, &numFrames, &fillBufList) if(numFrames == 0){ error = noErr; break; } sourceFrameOffset += numFrames error = ExtAudioFileWrite(destinationFile!, numFrames, &fillBufList) } ExtAudioFileDispose(destinationFile!) ExtAudioFileDispose(sourceFile!) }

El problema es audioConverter parece ser nulo en esta línea

error = AudioConverterGetProperty(audioConverter!, kAudioConverterPropertyCanResumeFromInterruption, &size, &canResume)

Y no puedo entender por qué. ¿Qué me perdí?


Omita AudioConverterGetProperty

En realidad no lo estás usando.
El siguiente fragmento convertirá un archivo de audio a AIFF: lee el archivo de origen en uno de los formatos compatibles, crea un codificador AIFF y lo recorre utilizando un buffer bufferByteSize . Los errores son levemente manejados.

Código completo, swift 3 :

func convertAudio(_ url: URL, outputURL: URL) { var error : OSStatus = noErr var destinationFile : ExtAudioFileRef? = nil var sourceFile : ExtAudioFileRef? = nil var srcFormat : AudioStreamBasicDescription = AudioStreamBasicDescription() var dstFormat : AudioStreamBasicDescription = AudioStreamBasicDescription() ExtAudioFileOpenURL(url as CFURL, &sourceFile) var thePropertySize: UInt32 = UInt32(MemoryLayout.stride(ofValue: srcFormat)) ExtAudioFileGetProperty(sourceFile!, kExtAudioFileProperty_FileDataFormat, &thePropertySize, &srcFormat) dstFormat.mSampleRate = 44100 //Set sample rate dstFormat.mFormatID = kAudioFormatLinearPCM dstFormat.mChannelsPerFrame = 1 dstFormat.mBitsPerChannel = 16 dstFormat.mBytesPerPacket = 2 * dstFormat.mChannelsPerFrame dstFormat.mBytesPerFrame = 2 * dstFormat.mChannelsPerFrame dstFormat.mFramesPerPacket = 1 dstFormat.mFormatFlags = kAudioFormatFlagIsBigEndian | kAudioFormatFlagIsSignedInteger // Create destination file error = ExtAudioFileCreateWithURL( outputURL as CFURL, kAudioFileAIFFType, &dstFormat, nil, AudioFileFlags.eraseFile.rawValue, &destinationFile) reportError(error: error) error = ExtAudioFileSetProperty(sourceFile!, kExtAudioFileProperty_ClientDataFormat, thePropertySize, &dstFormat) reportError(error: error) error = ExtAudioFileSetProperty(destinationFile!, kExtAudioFileProperty_ClientDataFormat, thePropertySize, &dstFormat) reportError(error: error) let bufferByteSize : UInt32 = 32768 var srcBuffer = [UInt8](repeating: 0, count: 32768) var sourceFrameOffset : ULONG = 0 while(true){ var fillBufList = AudioBufferList( mNumberBuffers: 1, mBuffers: AudioBuffer( mNumberChannels: 2, mDataByteSize: UInt32(srcBuffer.count), mData: &srcBuffer ) ) var numFrames : UInt32 = 0 if(dstFormat.mBytesPerFrame > 0){ numFrames = bufferByteSize / dstFormat.mBytesPerFrame } error = ExtAudioFileRead(sourceFile!, &numFrames, &fillBufList) reportError(error: error) if(numFrames == 0){ error = noErr; break; } sourceFrameOffset += numFrames error = ExtAudioFileWrite(destinationFile!, numFrames, &fillBufList) reportError(error: error) } error = ExtAudioFileDispose(destinationFile!) reportError(error: error) error = ExtAudioFileDispose(sourceFile!) reportError(error: error) }

Método de apoyo:

func reportError(error: OSStatus) { // Handle error }

Invocación:

let sourceUrl = URL(string: Bundle.main.path(forResource: "sample", ofType: "mp3")!) let paths = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true) let documentsDirectory = URL(string: paths.first!) let destUrl = documentsDirectory?.appendingPathComponent("converted.aiff") if let sourceUrl = sourceUrl, let destUrl = destUrl { print("from /(sourceUrl.absoluteString) to /(destUrl.absoluteString)") convertAudio(sourceUrl, outputURL: destUrl) }