3

我的应用程序中有一个用户录音和另一个 mp3 文件,我希望用户能够将这两个文件作为一个文件导出,这意味着这两个文件将以某种方式合并或相互叠加。

如果不理解,两个 mp3 文件将同时播放,就像用户可以通过乐器录制歌曲的任何应用程序一样。

录音和乐器是两个独立的 mp3 文件,需要作为一个文件导出。

我该怎么做呢?根据我的阅读,我找不到解决方案。我在连接两个音频文件时看到了很多,但我不希望它们一个接一个地播放,而是同时播放。

谢谢。

编辑:我知道这已经很晚了,但如果有人偶然发现并正在寻找示例代码,我的答案在这里:如何在 Xcode 中重叠音频文件并为 iPhone 组合?

4

2 回答 2

3

如果我猜对了,您是在要求音频混音器功能。这不是一项微不足道的任务。看看核心音频。一本好书就是这本。一种解决方案是创建一个无 GUI 的音频单元(混音器单元),它可以播放、混合和渲染两种信号(mp3)。

除了编程方面,这里还有一个音频工程方面:您应该注意信号的电平。想象一下,您有 2 个相同的 0dB 级别的 mp3。如果你把它们加起来,你的水平将是+3dB。这在数字世界中不存在(最大为 0dB)。因此,您必须在混音前降低输入电平。

编辑:抱歉输入迟了,但也许这对未来的人有帮助:Apple 有一个我刚刚偶然发现的音频混合器的例子。

于 2012-07-22T04:44:11.600 回答
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)
    }

})           }
于 2016-01-12T18:02:01.170 回答