I want to merge two or more .wav files to one and then convert it to .mp3 and this I would like to done in Swift (or at least to have option to include it to swift project).
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
I would like to post my working solution because I get so many thumbs up and answer from naresh doesn't help me much.
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"