iOS Code to Convert m4a to WAV

后端 未结 6 659
小鲜肉
小鲜肉 2020-12-14 13:48

Does anyone have any code snippets that show how to convert an M4a file to WAV? I know there are libraries that convert the other way around.

Thanks.

相关标签:
6条回答
  • 2020-12-14 14:04

    If anyone else needs some code to do this here it is in Swift

    func convertAudioFile(sourceURL: CFURLRef, destinationURL: 
    CFURLRef, outputFormat: OSType , 
    outputSampleRate: Float64) ->  OSStatus
    {
    var error : OSStatus = noErr
    var destinationFile : ExtAudioFileRef = nil
    var sourceFile : ExtAudioFileRef = nil
    
    var srcFormat : AudioStreamBasicDescription = AudioStreamBasicDescription()
    var dstFormat : AudioStreamBasicDescription = AudioStreamBasicDescription()
    
    var audioConverter : AudioConverterRef = nil
    
    audioConverter = AudioConverterRef.init()
    
    ExtAudioFileOpenURL(sourceURL, &sourceFile)
    
    var thePropertySize: UInt32 = UInt32(strideofValue(srcFormat))
    
    ExtAudioFileGetProperty(sourceFile, kExtAudioFileProperty_FileDataFormat, &thePropertySize, &srcFormat)
    
    dstFormat.mSampleRate = (outputSampleRate == 0 ? srcFormat.mSampleRate : outputSampleRate)  //Set sample rate
    
    dstFormat.mFormatID = outputFormat
    dstFormat.mChannelsPerFrame = 1
    dstFormat.mBitsPerChannel = 16
    dstFormat.mBytesPerPacket = 2 * dstFormat.mChannelsPerFrame
    dstFormat.mBytesPerFrame = 2 * dstFormat.mChannelsPerFrame
    dstFormat.mFramesPerPacket = 1
    dstFormat.mFormatFlags = kLinearPCMFormatFlagIsPacked | kLinearPCMFormatFlagIsSignedInteger // little-endian
    
    //Create destination file
    ExtAudioFileCreateWithURL(destinationURL, kAudioFileCAFType, &dstFormat, nil,
        AudioFileFlags.EraseFile.rawValue, &destinationFile)
    
    ExtAudioFileSetProperty(sourceFile, kExtAudioFileProperty_ClientDataFormat, thePropertySize, &dstFormat)
    ExtAudioFileSetProperty(destinationFile, kExtAudioFileProperty_ClientDataFormat, thePropertySize, &dstFormat)
    
    var size : UInt32 = UInt32(strideofValue(audioConverter))
    
    ExtAudioFileGetProperty(destinationFile, kExtAudioFileProperty_AudioConverter, &size, &audioConverter)
    
    var canResume : UInt32 = 0
    
    size = UInt32(strideofValue(canResume))
    
    error = AudioConverterGetProperty(audioConverter, kAudioConverterPropertyCanResumeFromInterruption, &size, &canResume)
    
    let bufferByteSize : UInt32 = 32768
    var srcBuffer = [UInt8](count: 32768, repeatedValue: 0)
    
    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)
    
    let audioAsset = AVURLAsset.init(URL: destinationURL, options: nil)
    if(audioAsset.duration.seconds < 5.0){
        error = -2500
    }
    
    return error;
    
    0 讨论(0)
  • 2020-12-14 14:16

    Here is an edit to @O2U answere. As above code does not actually convert it to wave file. Please use "kAudioFileWAVEType" instead of "kAudioFileCAFType" in above code at line //Create destination file ExtAudioFileCreateWithURL(destinationURL, kAudioFileCAFType, &dstFormat, nil, AudioFileFlags.EraseFile.rawValue, &destinationFile)

    0 讨论(0)
  • 2020-12-14 14:18

    I simply changed the extension of the file to .wav and removed the .m4a file and it worked.

    func getDirectory() -> URL {
        let path = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
        let documentDirectory = path[0]
        return documentDirectory
    }
    
    let date = Date().timeIntervalSince1970
    
    fileName = getDirectory().appendingPathComponent("\(date).m4a")
    wavFileName = getDirectory().appendingPathComponent("\(date).wav")
    
    try! FileManager.default.copyItem(at: fileName, to: wavFileName)
    try! FileManager.default.removeItem(at: fileName)
    

    I even played .wav file and it's working fine.

    audioPlayer = try! AVAudioPlayer(contentsOf: wavFileName)
    audioPlayer.play()
    

    Are there any drawbacks for converting the file extension from .m4a to .wav like this?

    0 讨论(0)
  • 2020-12-14 14:21

    Just to update for 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 = kLinearPCMFormatFlagIsPacked |
        kAudioFormatFlagIsSignedInteger
    
        // Create destination file
        error = ExtAudioFileCreateWithURL(
            outputURL as CFURL,
            kAudioFileWAVEType,
            &dstFormat,
            nil,
            AudioFileFlags.eraseFile.rawValue,
            &destinationFile)
        print("Error 1 in convertAudio: \(error.description)")
    
        error = ExtAudioFileSetProperty(sourceFile!,
                                        kExtAudioFileProperty_ClientDataFormat,
                                        thePropertySize,
                                        &dstFormat)
        print("Error 2 in convertAudio: \(error.description)")
    
        error = ExtAudioFileSetProperty(destinationFile!,
                                        kExtAudioFileProperty_ClientDataFormat,
                                        thePropertySize,
                                        &dstFormat)
        print("Error 3 in convertAudio: \(error.description)")
    
        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)
            print("Error 4 in convertAudio: \(error.description)")
    
            if(numFrames == 0){
                error = noErr;
                break;
            }
    
            sourceFrameOffset += numFrames
            error = ExtAudioFileWrite(destinationFile!, numFrames, &fillBufList)
            print("Error 5 in convertAudio: \(error.description)")
        }
    
        error = ExtAudioFileDispose(destinationFile!)
        print("Error 6 in convertAudio: \(error.description)")
        error = ExtAudioFileDispose(sourceFile!)
        print("Error 7 in convertAudio: \(error.description)")
    }
    
    0 讨论(0)
  • 2020-12-14 14:21

    AVAssetReader and AVAssetWriter in the AVFoundation framework can be used read AAC files and write that data as WAV/RIFF files on iOS devices. There's sample code on the Apple developer site. It's a bit more than a short snippet.

    0 讨论(0)
  • 2020-12-14 14:25

    Here is an Objective-C version of MScottWaller's Swift 3 answer. You need to @import AudioToolbox.

    -(void) convertAudio:(NSURL*)url outputURL:(NSURL*)outputURL
    {
        OSStatus error = noErr;
        ExtAudioFileRef destinationFile = nil;
        ExtAudioFileRef sourceFile = nil;
    
        AudioStreamBasicDescription srcFormat;
        AudioStreamBasicDescription dstFormat;
    
        ExtAudioFileOpenURL((__bridge CFURLRef)url, &sourceFile);
    
    
        UInt32 thePropertySize = sizeof(srcFormat); //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 = kLinearPCMFormatFlagIsPacked | kAudioFormatFlagIsSignedInteger;
    
        // Create destination file
        error = ExtAudioFileCreateWithURL(
                                          (__bridge CFURLRef)outputURL,
                                          kAudioFileWAVEType,
                                          &dstFormat,
                                          nil,
                                          kAudioFileFlags_EraseFile,
                                          &destinationFile);
        NSLog(@"Error 1 in convertAudio: %d - %@", error, [NSError errorWithDomain:NSOSStatusErrorDomain code:error userInfo:nil].description);
    
        error = ExtAudioFileSetProperty(sourceFile,
                                        kExtAudioFileProperty_ClientDataFormat,
                                        thePropertySize,
                                        &dstFormat);
        NSLog(@"Error 2 in convertAudio: %d - %@", error, [NSError errorWithDomain:NSOSStatusErrorDomain code:error userInfo:nil].description);
    
        error = ExtAudioFileSetProperty(destinationFile,
                                        kExtAudioFileProperty_ClientDataFormat,
                                        thePropertySize,
                                        &dstFormat);
        NSLog(@"Error 3 in convertAudio: %d - %@", error, [NSError errorWithDomain:NSOSStatusErrorDomain code:error userInfo:nil].description);
    
        const UInt32 bufferByteSize = 32768;
        UInt8 srcBuffer[bufferByteSize];// = [UInt8](repeating: 0, count: 32768)
        memset(srcBuffer, 0, bufferByteSize);
        unsigned long sourceFrameOffset = 0;
    
        while(true)
        {
            AudioBufferList fillBufList;
            fillBufList.mNumberBuffers = 1;
            fillBufList.mBuffers[0].mNumberChannels = 2;
            fillBufList.mBuffers[0].mDataByteSize = bufferByteSize;
            fillBufList.mBuffers[0].mData = &srcBuffer;
    
            UInt32 numFrames = 0;
    
            if(dstFormat.mBytesPerFrame > 0){
                numFrames = bufferByteSize / dstFormat.mBytesPerFrame;
            }
    
            error = ExtAudioFileRead(sourceFile, &numFrames, &fillBufList);
            NSLog(@"Error 4 in convertAudio: %d - %@", error, [NSError errorWithDomain:NSOSStatusErrorDomain code:error userInfo:nil].description);
    
            if(numFrames == 0)
            {
                error = noErr;
                break;
            }
    
            sourceFrameOffset += numFrames;
            error = ExtAudioFileWrite(destinationFile, numFrames, &fillBufList);
            NSLog(@"Error 5 in convertAudio: %d - %@", error, [NSError errorWithDomain:NSOSStatusErrorDomain code:error userInfo:nil].description);
        }
    
        error = ExtAudioFileDispose(destinationFile);
        NSLog(@"Error 6 in convertAudio: %d - %@", error, [NSError errorWithDomain:NSOSStatusErrorDomain code:error userInfo:nil].description);
        error = ExtAudioFileDispose(sourceFile);
        NSLog(@"Error 7 in convertAudio: %d - %@", error, [NSError errorWithDomain:NSOSStatusErrorDomain code:error userInfo:nil].description);
    }
    
    0 讨论(0)
提交回复
热议问题