How to combine 2 or 3 audio files in iOS?

I am new to Objective-C and have experience in just 5 months developing iPhone.

What I need:
I need to combine 2 or more audio files into one and export the result in aiff, mp3, caf or m4a format.

For example:
The first audio file containing “you need”, the second “download” and the third “document”.
Each sound part depends on the user's actions.

I spent 2 days without luck. This place is my last frontier.

I will be very grateful for the piece of code.

+7
source share
7 answers

The code below can be used to combine audio files.

Input files: Identifiers of the files that will be supplied in the audioIds array. For example. audio1.mp3, audio2.mp3 ... audioN.mp3 will be available in the document folder. Output file: mixed.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; } 
+22
source

You can use this method to combine three sounds.

 - (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
source

You should probably check out this post to do the same: Combine two audio files into one in the lens c

The answer is similar to what Ditar proposed. But 2 important things that you should keep in mind is that, firstly, it works only for mp3 format, and secondly, the transfer speed of all the files you are trying to combine should be the same, or only parts Your file will be played in the final output. It will stop playing where the data rate changes.

SSteve files, such as Wav files, have their own headers, and if you just write one file after another, it will only play the first file and then stop playing, which will mean that the file information shows a larger file size. this is because we do not have the information updated in the header of the first file.

+1
source

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 will probably require the input files to be of the same format and create the output file in the same format. If you need to convert the format, this can be better done after creating the output file.

0
source

I took two different mp3 files from AVMutableCompositionTrack. and these two mp3 files are stored in the same AVMutableComposition.

when I press the button, the path to the new mp3 will be shown by the 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
source

The easiest way to implement several aac combinations:

 - (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
source

I have an idea, not sure if it will work. Try to get NSData from these three files, add data to other NSData and then write. 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]; 

This is a theory, I'm not sure if this will work :), it really works if I open mp3 with a hex editor - copy everything and paste it at the end - then I have the same sound twice. Please try and let us know if this works.

-one
source

All Articles