在 iPhone 上合并音频文件

Posted

技术标签:

【中文标题】在 iPhone 上合并音频文件【英文标题】:merge Audio files on iPhone 【发布时间】:2010-07-29 03:35:33 【问题描述】:

我想在 iPhone 上将 .caf 文件和 .mp3 文件合并为 .mp3 文件,或者我可以将它们转换为 .aac 然后合并它们。我该怎么做? (就像 Kala OK,我想把我的声音和音乐融合在一起)

【问题讨论】:

您所说的“合并”是指将它们混合在一起吗?还是在同一个文件中一个接一个地整理它们? 就像 Kala OK,我想把我的声音和音乐融合在一起 【参考方案1】:

您需要将这两个文件解码为 LPCM(普通的旧整数),将它们添加/混合在一起,然后重新编码。 iPhone SDK 不支持 MP3 编码,所以需要重新编码为 AAC。

Apple 示例代码 iPhoneExtAudioFileConvertTest 将是一个很好的起点。

【讨论】:

我将两个 LPCM 文件混合在一起,然后通过 sdk 将其编码为 aac。 您的问题解决了吗?我遇到了同样的问题。【参考方案2】:

你可以用这个方法

- (BOOL) combineVoices1

    NSError *error = nil;
    BOOL ok = NO;


    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,    NSUserDomainMask, YES);
    NSString *documentsDirectory = [paths objectAtIndex:0];


    CMTime nextClipStartTime = kCMTimeZero;
    //Create AVMutableComposition Object.This object will hold our multiple AVMutableCompositionTrack.
    AVMutableComposition *composition = [[AVMutableComposition alloc] init];

    AVMutableCompositionTrack *compositionAudioTrack = [composition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid];
    [compositionAudioTrack setPreferredVolume:0.8];
    NSString *soundOne  =[[NSBundle mainBundle]pathForResource:@"test1" ofType:@"caf"];
    NSURL *url = [NSURL fileURLWithPath:soundOne];
    AVAsset *avAsset = [AVURLAsset URLAssetWithURL:url options:nil];
    NSArray *tracks = [avAsset tracksWithMediaType:AVMediaTypeAudio];
    AVAssetTrack *clipAudioTrack = [[avAsset tracksWithMediaType:AVMediaTypeAudio] objectAtIndex:0];
    [compositionAudioTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, avAsset.duration) ofTrack:clipAudioTrack atTime:kCMTimeZero error:nil];

    AVMutableCompositionTrack *compositionAudioTrack1 = [composition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid];
    [compositionAudioTrack setPreferredVolume:0.3];
    NSString *soundOne1  =[[NSBundle mainBundle]pathForResource:@"test" ofType:@"caf"];
    NSURL *url1 = [NSURL fileURLWithPath:soundOne1];
    AVAsset *avAsset1 = [AVURLAsset URLAssetWithURL:url1 options:nil];
    NSArray *tracks1 = [avAsset1 tracksWithMediaType:AVMediaTypeAudio];
    AVAssetTrack *clipAudioTrack1 = [[avAsset1 tracksWithMediaType:AVMediaTypeAudio] objectAtIndex:0];
    [compositionAudioTrack1 insertTimeRange:CMTimeRangeMake(kCMTimeZero, avAsset.duration) ofTrack:clipAudioTrack1 atTime:kCMTimeZero error:nil];


    AVMutableCompositionTrack *compositionAudioTrack2 = [composition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid];
    [compositionAudioTrack2 setPreferredVolume:1.0];
    NSString *soundOne2  =[[NSBundle mainBundle]pathForResource:@"song" ofType:@"caf"];
    NSURL *url2 = [NSURL fileURLWithPath:soundOne2];
    AVAsset *avAsset2 = [AVURLAsset URLAssetWithURL:url2 options:nil];
    NSArray *tracks2 = [avAsset2 tracksWithMediaType:AVMediaTypeAudio];
    AVAssetTrack *clipAudioTrack2 = [[avAsset2 tracksWithMediaType:AVMediaTypeAudio] objectAtIndex:0];
    [compositionAudioTrack1 insertTimeRange:CMTimeRangeMake(kCMTimeZero, avAsset2.duration) ofTrack:clipAudioTrack2 atTime:kCMTimeZero error:nil];



    AVAssetExportSession *exportSession = [AVAssetExportSession
                                           exportSessionWithAsset:composition
                                           presetName:AVAssetExportPresetAppleM4A];
    if (nil == exportSession) return NO;

    NSString *soundOneNew = [documentsDirectory stringByAppendingPathComponent:@"combined10.m4a"];
    //NSLog(@"Output file path - %@",soundOneNew);

    // configure export session  output with all our parameters
    exportSession.outputURL = [NSURL fileURLWithPath:soundOneNew]; // output path
    exportSession.outputFileType = AVFileTypeAppleM4A; // output file type

    // perform the export
    [exportSession exportAsynchronouslyWithCompletionHandler:^

        if (AVAssetExportSessionStatusCompleted == exportSession.status) 
            NSLog(@"AVAssetExportSessionStatusCompleted");
         else if (AVAssetExportSessionStatusFailed == exportSession.status) 
            // a failure may happen because of an event out of your control
            // for example, an interruption like a phone call comming in
            // make sure and handle this case appropriately
            NSLog(@"AVAssetExportSessionStatusFailed");
         else 
            NSLog(@"Export Session Status: %d", exportSession.status);
        
    ];


    return YES;



【讨论】:

【参考方案3】:

您可以使用 SDAVAssetExportSession 和以下代码将许多文件导出到 AAC:

-(void)mergeAudioFiles

    NSFileManager * fm = [[NSFileManager alloc] init];
    NSError * error;
    NSArray * filesNames = **NSArray of File Names;
    NSString * filePath = @"Dest File Name";
    NSString * pathToSave =[NSString stringWithFormat:@"%@%@",filePath,@".m4a"];

    CMTime startTime = kCMTimeZero;
    AVMutableComposition *composition = [AVMutableComposition composition];
    AVMutableCompositionTrack *compositionAudioTrack =[AVMutableCompositionTrack alloc];
    compositionAudioTrack = [composition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid];

    float audioEndTime=0;
    for (NSString *fileName in filesNames) 
        NSURL *audioUrl = [NSURL fileURLWithPath:fileName];
        AVURLAsset *audioasset = [[AVURLAsset alloc]initWithURL:audioUrl options:nil];
        CMTimeRange timeRange  = CMTimeRangeMake(kCMTimeZero, audioasset.duration);
        AVAssetTrack *audioAssetTrack= [[audioasset tracksWithMediaType:AVMediaTypeAudio] lastObject];
       [compositionAudioTrack insertTimeRange:timeRange ofTrack:audioAssetTrack atTime:startTime error:&error];
       startTime = CMTimeAdd(startTime, timeRange.duration);
       CMTime assetTime2 = [audioasset duration];
       Float64 duration2 = CMTimeGetSeconds(assetTime2);
       audioEndTime+=duration2;
    

    NSURL *exportUrl = [NSURL fileURLWithPath:pathToSave];

    float audiostartTime=0;
    CMTime startTime1 = CMTimeMake((int)(floor(audioStartTime * 100)), 100);
    CMTime stopTime = CMTimeMake((int)(ceil(audioEndTime * 100)), 100);
    CMTimeRange exportTimeRange = CMTimeRangeFromTimeToTime(startTime1, stopTime);


    SDAVAssetExportSession *encoder = [SDAVAssetExportSession.alloc initWithAsset:composition];
    encoder.outputFileType = AVFileTypeAppleM4A;
    encoder.outputURL = exportUrl;
    encoder.audioSettings = @
    
       AVFormatIDKey: @(kAudioFormatMPEG4AAC),
       AVNumberOfChannelsKey: @2,
       AVSampleRateKey: @44100,
       AVEncoderBitRateKey: @128000,
    ;
    encoder.timeRange = exportTimeRange;
    dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
    NSLog(@"Starting Audio Marge");
   [encoder exportAsynchronouslyWithCompletionHandler:^
   
        if (encoder.status == AVAssetExportSessionStatusCompleted)
        
            NSLog(@"Audio Marge succeeded");
            NSError * err = NULL;
            BOOL result = [fm moveItemAtPath:pathToSave toPath:filePath error:&err];
            if(!result) 
                NSLog(@"Error: %@", err);
            
            NSLog(@"Audio Copied");
         else if (encoder.status == AVAssetExportSessionStatusCancelled) 
            NSLog(@"Audio export cancelled");
         else 
           NSLog(@"Audio export failed with error: %@ (%ld)", encoder.error.localizedDescription, encoder.error.code);
        
        dispatch_semaphore_signal(semaphore);
   ];
   NSLog(@"Audio Wait to Finish");
   dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
  //cleanup
   for (NSString *fileName in filesNames) 
       [fm removeItemAtPath:fileName error:&error];
   
   NSLog(@"Audio Marge Finished");

【讨论】:

能否请您解释一下代码,因为这有助于在不逐行浏览的情况下了解代码【参考方案4】:

合并两个音频文件代码

-(void)mergeTwoAudioFile


    NSError * error;


    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);

    NSString *documentsDirectory = [[paths objectAtIndex:0] stringByAppendingPathComponent:@"Music_Directory"];


    //first audio path

    NSString *firstPath= [documentsDirectory stringByAppendingPathComponent:@"audio01.m4a"];

    NSURL *audioUrl1 = [NSURL fileURLWithPath:firstPath];


    AVMutableComposition *mixComposition = [AVMutableComposition composition];

    AVMutableCompositionTrack *audioCompositionTrack1 =[[AVMutableCompositionTrack alloc]init];

    AVURLAsset *audioasset1 = [[AVURLAsset alloc]initWithURL:audioUrl1 options:nil];
    AVAssetTrack *audioAssetTrack1= [[audioasset1 tracksWithMediaType:AVMediaTypeAudio] lastObject];

    audioCompositionTrack1 = [mixComposition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid];

    CMTime tempTime1= mixComposition.duration;

    [audioCompositionTrack1 insertTimeRange:CMTimeRangeMake(kCMTimeZero, audioasset1.duration) ofTrack:audioAssetTrack1 atTime:tempTime1 error:&error];



    //========second audio

    NSString *secondPath= [documentsDirectory stringByAppendingPathComponent:@"audio02.m4a"];
    NSURL *audioUrl2 = [NSURL fileURLWithPath:secondPath];
    AVMutableCompositionTrack *audioCompositionTrack2 =[[AVMutableCompositionTrack alloc]init];

    AVURLAsset *audioasset2 = [[AVURLAsset alloc]initWithURL:audioUrl2 options:nil];
    AVAssetTrack *audioAssetTrack2= [[audioasset2 tracksWithMediaType:AVMediaTypeAudio] lastObject];


    audioCompositionTrack2 = [mixComposition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid];

    CMTime tempTime2 = mixComposition.duration;

    [audioCompositionTrack2 insertTimeRange:CMTimeRangeMake(kCMTimeZero, audioasset2.duration) ofTrack:audioAssetTrack2 atTime:tempTime2 error:&error];


    NSString * pathToSave = [NSString stringWithFormat:@"finalTest.m4a"];
    pathToSave =[documentsDirectory stringByAppendingPathComponent:pathToSave];

    NSURL *movieUrl = [NSURL fileURLWithPath:pathToSave];

    AVAssetExportSession *exporter =[[AVAssetExportSession alloc] initWithAsset:mixComposition presetName:AVAssetExportPresetAppleM4A];
    exporter.shouldOptimizeForNetworkUse = YES;
    exporter.outputURL = movieUrl;

    exporter.outputFileType = AVFileTypeAppleM4A;



    //====================================================================

    float audioStartTime=0;

    CMTime assetTime1 = [audioasset1 duration];
    Float64 duration1 = CMTimeGetSeconds(assetTime1);

    CMTime assetTime2 = [audioasset2 duration];
    Float64 duration2 = CMTimeGetSeconds(assetTime2);

    float audioEndTime=duration1+duration2;


    CMTime startTime = CMTimeMake((int)(floor(audioStartTime * 100)), 100);

    CMTime stopTime = CMTimeMake((int)(ceil(audioEndTime * 100)), 100);

    CMTimeRange exportTimeRange = CMTimeRangeFromTimeToTime(startTime, stopTime);


    exporter.timeRange =exportTimeRange;
    //====================================================================

    [exporter exportAsynchronouslyWithCompletionHandler:^(void) 
        NSString* message;
        switch (exporter.status) 
            case AVAssetExportSessionStatusFailed:
                message = [NSString stringWithFormat:@"Export failed. Error: %@", exporter.error.description];
                NSLog(@"%@", message);
                break;
            case AVAssetExportSessionStatusCompleted: 
                message = [NSString stringWithFormat:@"Export completed"];
                NSLog(@"%@", message);

                break;
            case AVAssetExportSessionStatusCancelled:
                message = [NSString stringWithFormat:@"Export cancelled!"];
                NSLog(@"%@", message);
                break;
            default:
                NSLog(@"Export unhandled status: %ld", (long)exporter.status);
                break;
        
    ];

【讨论】:

以上是关于在 iPhone 上合并音频文件的主要内容,如果未能解决你的问题,请参考以下文章

合并iPhone上的音频文件

如何在 iphone sdk 中合并音频和视频

iPhone合并UIImage和CAF Audio到AV文件

iphone 5 无法播放音频文件

Unity - 音频文件在 iPhone 和 iPad 上播放不佳

handleWatchKitExtensionRequest 在 iphone 上播放背景音频