我的应用程序中有一个用户录制和另一个mp3文件,我希望用户能够将这两个文件导出为一个,这意味着这两个文件将以某种方式合并或相互叠加。
如果不理解,两个mp3文件将同时播放,就像用户可以录制的任何应用程序,歌曲,乐器一样。
录音和乐器是两个独立的mp3文件,需要导出为一个。
我该怎么做呢?从我读过的,我找不到解决方案。我在连接两个音频文件时看到了很多,但我不希望它们一个接一个地播放,而是在同一时间播放。
感谢。
编辑:我知道这已经很晚了,但是如果有人因此而发现并且正在寻找示例代码,那么我的答案就在这里:How can I overlap audio files and combine for iPhone in Xcode?答案 0 :(得分:3)
如果我找到你,你就要求使用音频混音器功能。这不是一项微不足道的任务。 看看Core Audio。一本好书开始是this one。 一种解决方案是创建一个无GUI的音频单元(混音器单元),播放,混合和渲染两个信号(mp3)。
除了编程方面,这里还有音频工程方面:你应该注意信号的高低。想象一下,你有2个相同的mp3,在0dB的水平。如果你总结一下,你的等级将是+ 3dB。这在数字世界中不存在(0dB最大)。因此,您必须在混合之前降低输入水平。
编辑:对于迟到的输入感到抱歉,但也许这有助于将来的某个人:Apple has an example我刚刚完成的音频混音器。
答案 1 :(得分:3)
如果您在2016年阅读此内容并且您正在寻找swift 2.x中的解决方案 - 我找到了您。我的解决方案实现了一个闭包,在写入后返回输出文件,以避免因为操作是异步操作而立即读取零字节文件。这通过使用第一个音轨的持续时间作为总输出持续时间来重叠两个音轨。
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)
}
}) }