Reputation: 574
I have a user recording and another mp3 file in my app, and I want the user to be able to export both of these as one, meaning the two files will be merged or laid over each other in some way.
In case that wasn't understood, both mp3 files are to be played at the same time just as any app where a user can record say, a song, over an instrumental.
The recording and the instrumental are two separate mp3 files that need to be exported as one.
How do I go about doing this? From what I've read, I can't find the solution. I see a lot on concatenating the two audio files, but I don't want them to play one after another, but rather at the same time.
Thanks.
EDIT: I know this is late, but in case anyone stumbles by this and was looking for sample code, it's in my answer here: How can I overlap audio files and combine for iPhone in Xcode?
Upvotes: 3
Views: 5679
Reputation: 136
If you are reading this in 2016 and you're looking for a solution in swift 2.x - I got you. My solution implements a closure to return the outputfile after it has been written to avoid reading a file of zero byte immediately since the operation is an asynchronous one. This is particularly for overlapping two audio tracks by using the duration of the first track as the total output duration.
func setUpAndAddAudioAtPath(assetURL: NSURL, toComposition composition: AVMutableComposition, duration: CMTime) {
let songAsset: AVURLAsset = AVURLAsset(URL: assetURL, options: nil)
let track: AVMutableCompositionTrack = composition.addMutableTrackWithMediaType(AVMediaTypeAudio, preferredTrackID: kCMPersistentTrackID_Invalid)
let sourceAudioTrack: AVAssetTrack = songAsset.tracksWithMediaType(AVMediaTypeAudio)[0]
var error: NSError? = nil
var ok: Bool = false
let startTime: CMTime = CMTimeMakeWithSeconds(0, 1)
let trackDuration: CMTime = songAsset.duration
//CMTime longestTime = CMTimeMake(848896, 44100); //(19.24 seconds)
let tRange: CMTimeRange = CMTimeRangeMake(startTime, duration)
//Set Volume
let trackMix: AVMutableAudioMixInputParameters = AVMutableAudioMixInputParameters(track: track)
trackMix.setVolume(1.0, atTime: kCMTimeZero)
audioMixParams.append(trackMix)
//Insert audio into track
try! track.insertTimeRange(tRange, ofTrack: sourceAudioTrack, atTime: CMTimeMake(0, 44100))}
func saveRecording(audio1: NSURL, audio2: NSURL, callback: (url: NSURL?, error: NSError?)->()) {
let composition: AVMutableComposition = AVMutableComposition()
//Add Audio Tracks to Composition
let avAsset1 = AVURLAsset(URL: audio1, options: nil)
var track1 = avAsset1.tracksWithMediaType(AVMediaTypeAudio)
let assetTrack1:AVAssetTrack = track1[0]
let duration: CMTime = assetTrack1.timeRange.duration
setUpAndAddAudioAtPath(audio1, toComposition: composition, duration: duration)
setUpAndAddAudioAtPath(audio2, toComposition: composition, duration: duration)
let audioMix: AVMutableAudioMix = AVMutableAudioMix()
audioMix.inputParameters = audioMixParams
//If you need to query what formats you can export to, here's a way to find out
NSLog("compatible presets for songAsset: %@", AVAssetExportSession.exportPresetsCompatibleWithAsset(composition))
let format = NSDateFormatter()
format.dateFormat="yyyy-MM-dd-HH-mm-ss"
let currentFileName = "recording-\(format.stringFromDate(NSDate()))-merge.m4a"
let documentsDirectory = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask)[0]
let outputUrl = documentsDirectory.URLByAppendingPathComponent(currentFileName)
let assetExport = AVAssetExportSession(asset: composition, presetName: AVAssetExportPresetAppleM4A)
assetExport!.outputFileType = AVFileTypeAppleM4A
assetExport!.outputURL = outputUrl
assetExport!.exportAsynchronouslyWithCompletionHandler({
audioMixParams.removeAll()
switch assetExport!.status{
case AVAssetExportSessionStatus.Failed:
print("failed \(assetExport!.error)")
callback(url: nil, error: assetExport!.error)
case AVAssetExportSessionStatus.Cancelled:
print("cancelled \(assetExport!.error)")
callback(url: nil, error: assetExport!.error)
default:
print("complete")
callback(url: outputUrl, error: nil)
}
}) }
Upvotes: 3
Reputation: 12884
If I get you right, you are asking for a audio mixer feature. This is not a trivial task. Take a look at Core Audio. A good book to start with is this one. One solution would be, to create a GUI-less Audio Unit (mixer unit) that plays, mixes and renders both signal (mp3s).
Besides the programming aspect, there is also an audio engineering aspect here: you should take care of the level of the signals. Imagine you have 2 identical mp3s at a level of 0dB. If you sum them up, your level will be +3dB. This don't exist in the digital world (0dB ist the maximum). Because of that, you would have to reduce the input levels before mixing.
EDIT: sorry for the late input, but maybe this helps someone in the future: Apple has an example for the Audio Mixer that I just stumpled upon.
Upvotes: 3