iOS Swift - Merge and convert .wav files to .mp3

 ̄綄美尐妖づ 提交于 2019-12-02 22:35:32

I would like to post my working solution because I get so many thumbs up and answer from naresh doesn't help me much.

  1. I have generated lame.framework library from this project https://github.com/wuqiong/mp3lame-for-iOS
  2. I've added library to my Swift project (Build Phases -> Link Binary With Libraries)
  3. I've created wrapper for using c functions in Objective C and by bridging header I use it in Swift.
  4. For concatenate wav files I use AVAssetExportSession with Swift

And now source codes. So first wrapper. It's class for converting .wav files to .mp3. There could be many changes (maybe parameter for output file and other options) but I think everyone could change it. I guess this could be rewritten to Swift but I wasn't sure how to do it. So it's Objective C class:

#import "AudioWrapper.h"
#import "lame/lame.h"

@implementation AudioWrapper

+ (void)convertFromWavToMp3:(NSString *)filePath {


    NSString *mp3FileName = @"Mp3File";
    mp3FileName = [mp3FileName stringByAppendingString:@".mp3"];
    NSString *mp3FilePath = [NSTemporaryDirectory() stringByAppendingPathComponent:mp3FileName];

    NSLog(@"%@", mp3FilePath);

    @try {
        int read, write;

        FILE *pcm = fopen([filePath cStringUsingEncoding:1], "rb");  //source
        fseek(pcm, 4*1024, SEEK_CUR);                                   //skip file header
        FILE *mp3 = fopen([mp3FilePath cStringUsingEncoding:1], "wb");  //output

        const int PCM_SIZE = 8192;
        const int MP3_SIZE = 8192;
        short int pcm_buffer[PCM_SIZE*2];
        unsigned char mp3_buffer[MP3_SIZE];

        lame_t lame = lame_init();
        lame_set_in_samplerate(lame, 44100);
        lame_set_VBR(lame, vbr_default);
        lame_init_params(lame);

        do {
            read = fread(pcm_buffer, 2*sizeof(short int), PCM_SIZE, pcm);
            if (read == 0)
                write = lame_encode_flush(lame, mp3_buffer, MP3_SIZE);
            else
                write = lame_encode_buffer_interleaved(lame, pcm_buffer, read, mp3_buffer, MP3_SIZE);

            fwrite(mp3_buffer, write, 1, mp3);

        } while (read != 0);

        lame_close(lame);
        fclose(mp3);
        fclose(pcm);
    }
    @catch (NSException *exception) {
        NSLog(@"%@",[exception description]);
    }
    @finally {
        [self performSelectorOnMainThread:@selector(convertMp3Finish)
                               withObject:nil
                            waitUntilDone:YES];
    }
}

Swift AudioHelper class for concatening audio files and calling method for converting .wav file to .mp3:

import UIKit
import AVFoundation


protocol AudioHelperDelegate {
    func assetExportSessionDidFinishExport(session: AVAssetExportSession, outputUrl: NSURL)
}

class AudioHelper: NSObject {

    var delegate: AudioHelperDelegate?

    func concatenate(audioUrls: [NSURL]) {

        //Create AVMutableComposition Object.This object will hold our multiple AVMutableCompositionTrack.
        var composition = AVMutableComposition()
        var compositionAudioTrack:AVMutableCompositionTrack = composition.addMutableTrackWithMediaType(AVMediaTypeAudio, preferredTrackID: CMPersistentTrackID())

        //create new file to receive data
        var documentDirectoryURL = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask).first! as! NSURL
        var fileDestinationUrl = NSURL(fileURLWithPath: NSTemporaryDirectory().stringByAppendingPathComponent("resultmerge.wav"))
        println(fileDestinationUrl)

        StorageManager.sharedInstance.deleteFileAtPath(NSTemporaryDirectory().stringByAppendingPathComponent("resultmerge.wav"))

        var avAssets: [AVURLAsset] = []
        var assetTracks: [AVAssetTrack] = []
        var durations: [CMTime] = []
        var timeRanges: [CMTimeRange] = []

        var insertTime = kCMTimeZero

        for audioUrl in audioUrls {
            let avAsset = AVURLAsset(URL: audioUrl, options: nil)
            avAssets.append(avAsset)

            let assetTrack = avAsset.tracksWithMediaType(AVMediaTypeAudio)[0] as! AVAssetTrack
            assetTracks.append(assetTrack)

            let duration = assetTrack.timeRange.duration
            durations.append(duration)

            let timeRange = CMTimeRangeMake(kCMTimeZero, duration)
            timeRanges.append(timeRange)

            compositionAudioTrack.insertTimeRange(timeRange, ofTrack: assetTrack, atTime: insertTime, error: nil)
            insertTime = CMTimeAdd(insertTime, duration)
        }

        //AVAssetExportPresetPassthrough => concatenation
        var assetExport = AVAssetExportSession(asset: composition, presetName: AVAssetExportPresetPassthrough)
        assetExport.outputFileType = AVFileTypeWAVE
        assetExport.outputURL = fileDestinationUrl
        assetExport.exportAsynchronouslyWithCompletionHandler({
            self.delegate?.assetExportSessionDidFinishExport(assetExport, outputUrl: fileDestinationUrl!)
        })
    }

    func exportTempWavAsMp3() {

        let wavFilePath = NSTemporaryDirectory().stringByAppendingPathComponent("resultmerge.wav")
        AudioWrapper.convertFromWavToMp3(wavFilePath)
    }
}

Bridging header contains:

#import "lame/lame.h"
#import "AudioWrapper.h"

We have dedicated classes to read/write media from/to a file they are AVAssetReader and AVAssetWriter and with the help of AVAssetExportSession you can export it as mp3 file. or else you can use https://github.com/michaeltyson/TPAACAudioConverter

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!