How to concatenate 2 or 3 audio files in iOS?

后端 未结 7 1532
不知归路
不知归路 2020-12-08 12:19

I am newcomer in Objective-C and have experience only 5 months in iPhone development.

What I need:
I need to concatenate 2 or more

相关标签:
7条回答
  • 2020-12-08 12:34

    Code below can be used to merge audio files.

    Input files: Ids of the files to be supplied in array audioIds. Eg. audio1.mp3, audio2.mp3 … audioN.mp3 to be available in documents folder Output file: combined.m4a

         - (BOOL) combineVoices {
    
           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];
    
         for (int i = 0; i< [self.audioIds count]; i++) {
            int key = [[self.audioIds objectAtIndex:i] intValue];
            NSString *audioFileName = [NSString stringWithFormat:@"audio%d", key];
    
            //Build the filename with path
            NSString *soundOne = [documentsDirectory stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.mp3", audioFileName]];
            //NSLog(@"voice file - %@",soundOne);
    
            NSURL *url = [NSURL fileURLWithPath:soundOne];    
            AVAsset *avAsset = [AVURLAsset URLAssetWithURL:url options:nil];
            NSArray *tracks = [avAsset tracksWithMediaType:AVMediaTypeAudio];
            if ([tracks count] == 0) 
                return NO;
            CMTimeRange timeRangeInAsset = CMTimeRangeMake(kCMTimeZero, [avAsset duration]);
            AVAssetTrack *clipAudioTrack = [[avAsset tracksWithMediaType:AVMediaTypeAudio] objectAtIndex:0];
            ok = [compositionAudioTrack insertTimeRange:timeRangeInAsset  ofTrack:clipAudioTrack atTime:nextClipStartTime error:&error];
            if (!ok) {
                NSLog(@"Current Video Track Error: %@",error);
            }
            nextClipStartTime = CMTimeAdd(nextClipStartTime, timeRangeInAsset.duration);
        }
    
        // create the export session
        // no need for a retain here, the session will be retained by the
        // completion handler since it is referenced there
        AVAssetExportSession *exportSession = [AVAssetExportSession
                                               exportSessionWithAsset:composition
                                               presetName:AVAssetExportPresetAppleM4A];
        if (nil == exportSession) return NO;
    
        NSString *soundOneNew = [documentsDirectory stringByAppendingPathComponent:@"combined.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;
    }
    
    0 讨论(0)
  • 2020-12-08 12:45

    I have an idea, not sure it will work. Try to get NSData from these 3 files, append the data into another NSData and then write it. Something like:

    NSMutableData *concatenatedData = [NSMutableData alloc] init];
    NSData *data1 = [[NSData alloc] initWithContentsOfFile:(NSString *)path];
    NSData *data2 = [[NSData alloc] initWithContentsOfFile:(NSString *)path];
    NSData *data3 = [[NSData alloc] initWithContentsOfFile:(NSString *)path];
    [concatenatedData appendData: data1];
    [concatenatedData appendData: data2];
    [concatenatedData appendData: data3];
    [concatenatedData writeToFile:@"/path/to/concatenatedData.mp3" atomically:YES];
    

    It's a theory I'm not sure it will work :), it actually works if i open an mp3 with hex editor - copy everything and paste it in the end - then I have the same sound twice. Please try it and let us know if it works.

    0 讨论(0)
  • 2020-12-08 12:48

    The easiest way to implement multiple combinations of aac:

    - (NSString *)concatenatedAACVoicesPath{
    NSMutableData *concatenatedData = [[NSMutableData alloc] init];
    
    NSArray *aacPathArr = [self queryAAC];
    for (NSString *path in aacPathArr) {
        NSData *data = [[NSData alloc] initWithContentsOfFile:path];
        [concatenatedData appendData: data];
    }
    
    NSString *fileNamePath = [NSString stringWithFormat:@"%@/%@.aac",[NSString createPath:currRecordDocName],currRecordDocName];
    [concatenatedData writeToFile:fileNamePath atomically:YES];
    
    return fileNamePath;
    

    }

    0 讨论(0)
  • 2020-12-08 12:50

    You can use this method to merge 3 sounds together.

    - (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;
    
    
    }
    
    0 讨论(0)
  • 2020-12-08 12:52

    I have taken two diffrent mp3 files from AVMutableCompositionTrack. and these two mp3 files are stored in same AVMutableComposition.

    when i will press the button the path of new mp3 will be shown by console.

    -(IBAction)play
    {
        [self mixAudio];    
    }
    
    -(void)mixAudio
     {
        CFAbsoluteTime currentTime=CFAbsoluteTimeGetCurrent();
        AVMutableComposition *composition = [[AVMutableComposition alloc] init];
    
        AVMutableCompositionTrack *compositionAudioTrack = [composition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid];
        [compositionAudioTrack setPreferredVolume:0.8];
        NSString *soundOne  =[[NSBundle mainBundle]pathForResource:@"KICK1" ofType:@"mp3"];
        NSURL *url = [NSURL fileURLWithPath:soundOne];
        AVAsset *avAsset = [AVURLAsset URLAssetWithURL:url options:nil];
        NSArray *tracks = [avAsset tracksWithMediaType:AVMediaTypeAudio];
        AVAssetTrack *clipAudioTrack = [tracks 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.8];
        NSString *soundOne1  =[[NSBundle mainBundle]pathForResource:@"KICK2" ofType:@"mp3"];
        NSURL *url1 = [NSURL fileURLWithPath:soundOne1];
        AVAsset *avAsset1 = [AVURLAsset URLAssetWithURL:url1 options:nil];
        NSArray *tracks1 = [avAsset1 tracksWithMediaType:AVMediaTypeAudio];
        AVAssetTrack *clipAudioTrack1 = [tracks1 objectAtIndex:0];
        [compositionAudioTrack1 insertTimeRange:CMTimeRangeMake(kCMTimeZero, avAsset1.duration) ofTrack:clipAudioTrack1 atTime: kCMTimeZero error:nil];
    
        NSArray *paths = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES);
        NSString *libraryCachesDirectory = [paths objectAtIndex:0];
        NSString *strOutputFilePath = [libraryCachesDirectory stringByAppendingPathComponent:@"output.mov"];
        NSString *requiredOutputPath = [libraryCachesDirectory stringByAppendingPathComponent:@"output.m4a"];
        NSURL *audioFileOutput = [NSURL fileURLWithPath:requiredOutputPath];
        [[NSFileManager defaultManager] removeItemAtURL:audioFileOutput error:NULL];
    
        AVAssetExportSession *exporter=[[AVAssetExportSession alloc] initWithAsset:composition presetName:AVAssetExportPresetAppleM4A];
        exporter.outputURL=audioFileOutput;
        exporter.outputFileType=AVFileTypeAppleM4A;
    
        [exporter exportAsynchronouslyWithCompletionHandler:^{
    
            NSLog(@" OUtput path is \n %@", requiredOutputPath);
            NSFileManager * fm = [[NSFileManager alloc] init];
            [fm moveItemAtPath:strOutputFilePath toPath:requiredOutputPath error:nil];
    
             NSLog(@" OUtput path is \n %@", requiredOutputPath);
            NSLog(@"export complete: %lf",CFAbsoluteTimeGetCurrent()-currentTime);
            NSError *error;
            audioPlayer=[[AVAudioPlayer alloc]initWithContentsOfURL:audioFileOutput error:&error];
            audioPlayer.numberOfLoops=0;
            [audioPlayer play];
    
        }];
    
    }
    
    0 讨论(0)
  • 2020-12-08 12:53

    Have you tried something like this:

    AudioFileCreateWithURL //to create the output file
    For each input file:
        AudioFileOpenURL //open file
        repeat
            AudioFileReadBytes //read from input file
            AudioFileWriteBytes //write to output file
        until eof(input file)
        AudioFileClose //close input file
    AudioFileClose //close output file
    

    This would probably require that the input files are all the same format and would create the output file in that same format. If you need to convert the format, that might be better done after creating the output file.

    0 讨论(0)
提交回复
热议问题