Как объединить 2 или 3 аудиофайла в iOS? - PullRequest
10 голосов
/ 11 июля 2011

Я новичок в Objective-C и имею опыт разработки iPhone только 5 месяцев.

Что мне нужно:
Мне нужно объединить 2 или более аудиофайлов в один и экспортировать результаты в формате aiff, mp3, caf или m4a.

Например:
Первый аудиофайл, содержащий «Вам нужно», второй «загрузить» и третий «документ».
Каждая аудио часть зависит от действий пользователя.

Я провел 2 дня без удачи. Это место - мой последний рубеж.

Я буду очень признателен за кусок кода.

Ответы [ 7 ]

24 голосов
/ 12 мая 2012

Код ниже может использоваться для объединения аудиофайлов.

Входные файлы: идентификаторы файлов, которые будут предоставлены в массиве audioIds.Например.audio1.mp3, audio2.mp3… audioN.mp3 должен быть доступен в папке документов. Выходной файл: комбинированный. 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;
}
3 голосов
/ 10 апреля 2013

Вы можете использовать этот метод для объединения 3 звуков вместе.

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


}
1 голос
/ 19 августа 2012

Вероятно, вам следует заглянуть в этот пост, чтобы сделать то же самое: Объединить два аудиофайла в один в задаче c

Ответ похож на то, что предложил Димитар.Но две важные вещи, которые вы должны иметь в виду, это то, что, во-первых, он работает только для формата mp3, а во-вторых, скорость передачи всех файлов, которые вы пытаетесь объединить, должна быть одинаковой, иначе только части вашего файла будутиграть в финальный выход.Он перестанет воспроизводиться при изменении битрейта.

SSteve - файлы, подобные файлам Wav, имеют свои собственные заголовки, и если вы просто записываете один файл за другим, он воспроизводит только первый файл, а затем останавливает воспроизведение, несмотрячто информация о файле показывает больший размер файла.это потому, что у нас нет обновленной информации в заголовке первого файла.

0 голосов
/ 04 мая 2016

Самый простой способ реализовать несколько комбинаций 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 голосов
/ 06 августа 2014

Я взял два разных mp3-файла из AVMutableCompositionTrack. и эти два mp3-файла хранятся в одной AVMutableComposition.

когда я нажму кнопку, путь нового mp3 будет показан консолью.

-(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 голосов
/ 25 августа 2011

Вы пробовали что-то вроде этого:

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

Это, вероятно, потребовало бы, чтобы все входные файлы имели одинаковый формат и создавало бы выходной файл в том же формате.Если вам нужно преобразовать формат, это может быть лучше сделано после создания выходного файла.

0 голосов
/ 17 июля 2011

У меня есть идея, не уверен, что она будет работать.Попробуйте получить NSData из этих 3 файлов, добавить данные в другой NSData и затем записать его.Что-то вроде:

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];

Это теория, я не уверен, что она будет работать :), она действительно работает, если я открываю mp3 с помощью hex-редактора - копирую все и вставляю его в конце - тогда у меня естьодин и тот же звук дважды.Пожалуйста, попробуйте и дайте нам знать, если это работает.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...