14

I searched a lot and couldn't find anything relevant... I am working on iOS audio files and here is what I want to do...

  1. Record Audio and Save Clip (Checked, I did this using AVAudioRecorder)
  2. Change the pitch (Checked, Did this using Dirac)
  3. Trimming :(

I have two markers i.e. starting & ending offset and using this info I want to trim recorded file and want to save it back. I don't want to use "seek" because later on I want to play all recorded files in sync (just like flash movie clips in timeline) and then finally I want to export as one audio file.

inorganik
  • 24,255
  • 17
  • 90
  • 114
Muhammad Usama
  • 247
  • 1
  • 2
  • 8

4 Answers4

31

Here's the code that I've used to trim audio from a pre-existing file. You'll need to change the M4A related constants if you've saved or are saving to another format.

- (BOOL)trimAudio
{
    float vocalStartMarker = <starting time>;
    float vocalEndMarker = <ending time>;

    NSURL *audioFileInput = <your pre-existing file>;
    NSURL *audioFileOutput = <the file you want to create>;

    if (!audioFileInput || !audioFileOutput)
    {
        return NO;
    }

    [[NSFileManager defaultManager] removeItemAtURL:audioFileOutput error:NULL];
    AVAsset *asset = [AVAsset assetWithURL:audioFileInput];

    AVAssetExportSession *exportSession = [AVAssetExportSession exportSessionWithAsset:asset
                                                                            presetName:AVAssetExportPresetAppleM4A];

    if (exportSession == nil)
    {        
        return NO;
    }

    CMTime startTime = CMTimeMake((int)(floor(vocalStartMarker * 100)), 100);
    CMTime stopTime = CMTimeMake((int)(ceil(vocalEndMarker * 100)), 100);
    CMTimeRange exportTimeRange = CMTimeRangeFromTimeToTime(startTime, stopTime);

    exportSession.outputURL = audioFileOutput;
    exportSession.outputFileType = AVFileTypeAppleM4A;
    exportSession.timeRange = exportTimeRange;

    [exportSession exportAsynchronouslyWithCompletionHandler:^
     {
         if (AVAssetExportSessionStatusCompleted == exportSession.status)
         {
             // It worked!
         } 
         else if (AVAssetExportSessionStatusFailed == exportSession.status)
         {
             // It failed...
         }
     }];

    return YES;
}

There's also Technical Q&A 1730, which gives a slightly more detailed approach.

kyleobrien
  • 1,551
  • 14
  • 8
  • vocalStartMarker and vocalEndMarker is in range [0,1], right? – Hai Hw Nov 28 '13 at 11:02
  • 1
    vocalStartMarker and vocalEndMarker are in seconds. For example, trimming the middle second of a 10 second clip, you'd set vocalStartMarker = 4.5 and vocalEndMarker = 5.5. – kyleobrien Dec 03 '13 at 20:42
  • I think we just use: CMTime startTime = CMTimeMake(vocalStartMarker, 1); – Hai Hw Dec 10 '13 at 07:39
  • How do I specify the audio bitrate when export to m4a format ? – moligaloo Mar 08 '15 at 13:38
  • i am using same code for trim 15 second audio but i am getting different seconds every time. like 19, 16, 15 seconds. here is code : float vocalStartMarker = 0.0f; float vocalEndMarker = 15.0f; CMTime startTime = CMTimeMake((int)(floor(vocalStartMarker * 100)), 100); CMTime stopTime = CMTimeMake((int)(ceil(vocalEndMarker * 100)), 100); CMTimeRange exportTimeRange = CMTimeRangeFromTimeToTime(startTime, stopTime); – iVarun Dec 09 '16 at 06:20
  • I couldn't find any answer for how to delete from an audio file, for example if I want to delete from second 3 till 10. can u check this question please: https://stackoverflow.com/questions/53928988/swift-how-to-delete-part-of-audio – mahdi Dec 26 '18 at 11:07
3

import following two libraries in .m

#import "BJRangeSliderWithProgress.h"
#import  < AVFoundation/AVFoundation.h >

and after that paste following code you will be able to trim an audio file with the help of two thumbs.

- (void) viewDidLoad
{
      [super viewDidLoad];
    // Do any additional setup after loading the view from its nib.

       mySlider = [[BJRangeSliderWithProgress alloc] initWithFrame:CGRectMake(20, 100, 300, 50)];

      [mySlider setDisplayMode:BJRSWPAudioSetTrimMode];

      [mySlider addTarget:self action:@selector(valueChanged) forControlEvents:UIControlEventValueChanged];

      [mySlider setMinValue:0.0];

      NSString *strInputFilePath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"saewill.mp3"];

      NSURL *audioFileInput = [NSURL fileURLWithPath:strInputFilePath];

      audioPlayer=[[AVAudioPlayer alloc]initWithContentsOfURL:audioFileInput error:nil];

      [mySlider setMaxValue:audioPlayer.duration];

      [self.view addSubview:mySlider];
}

-(void)valueChanged {
      NSLog(@"%f %f", mySlider.leftValue, mySlider.rightValue);
}


-(IBAction)playTheSong
{
      // Path of your source audio file
      NSString *strInputFilePath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"saewill.mp3"];
      NSURL *audioFileInput = [NSURL fileURLWithPath:strInputFilePath];

      // Path of your destination save audio file
      NSArray *paths = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES);
      NSString *libraryCachesDirectory = [paths objectAtIndex:0];
      //libraryCachesDirectory = [libraryCachesDirectory stringByAppendingPathComponent:@"Caches"];

      NSString *strOutputFilePath = [libraryCachesDirectory stringByAppendingPathComponent:@"output.mov"];
      NSString *requiredOutputPath = [libraryCachesDirectory stringByAppendingPathComponent:@"output.m4a"];
      NSURL *audioFileOutput = [NSURL fileURLWithPath:requiredOutputPath];

      [[NSFileManager defaultManager] removeItemAtURL:audioFileOutput error:NULL];
      AVAsset *asset = [AVAsset assetWithURL:audioFileInput];

      AVAssetExportSession *exportSession = [AVAssetExportSession exportSessionWithAsset:asset
                                                                              presetName:AVAssetExportPresetAppleM4A];


      float startTrimTime = mySlider.leftValue;
      float endTrimTime = mySlider.rightValue;

      CMTime startTime = CMTimeMake((int)(floor(startTrimTime * 100)), 100);
      CMTime stopTime = CMTimeMake((int)(ceil(endTrimTime * 100)), 100);
      CMTimeRange exportTimeRange = CMTimeRangeFromTimeToTime(startTime, stopTime);

      exportSession.outputURL = audioFileOutput;
      exportSession.outputFileType = AVFileTypeAppleM4A;
      exportSession.timeRange = exportTimeRange;

      [exportSession exportAsynchronouslyWithCompletionHandler:^
       {
           if (AVAssetExportSessionStatusCompleted == exportSession.status)
           {
               NSLog(@"Success!");
               NSLog(@" OUtput path is \n %@", requiredOutputPath);
               NSFileManager * fm = [[NSFileManager alloc] init];
               [fm moveItemAtPath:strOutputFilePath toPath:requiredOutputPath error:nil];
               //[[NSFileManager defaultManager] removeItemAtURL:audioFileOutput error:NULL];

               NSURL *url=[NSURL fileURLWithPath:requiredOutputPath];
               NSError *error;
               audioPlayer=[[AVAudioPlayer alloc]initWithContentsOfURL:url error:&error];
               audioPlayer.numberOfLoops=0;
               [audioPlayer play];

           }
           else if (AVAssetExportSessionStatusFailed == exportSession.status)
           {
               NSLog(@"failed with error: %@", exportSession.error.localizedDescription);
           }
       }];

}
Roozbeh Zabihollahi
  • 7,207
  • 45
  • 39
  • You could make this answer better by adding a few comments about what is going on – arghtype Jul 29 '14 at 13:39
  • there will be a slider on the screen and there will be two thumbs. with the help of thumbs you will be able to trim the audio(.m4a). @iwantMyAnswerNow – Sumit Srivastava Jul 30 '14 at 06:39
3

// Swift 4.2

If anybody is still looking for answer in swift here it is.

//Audio Trimming

func trimAudio(asset: AVAsset, startTime: Double, stopTime: Double, finished:@escaping (URL) -> ())
{

        let compatiblePresets = AVAssetExportSession.exportPresets(compatibleWith:asset)

        if compatiblePresets.contains(AVAssetExportPresetMediumQuality) {

        guard let exportSession = AVAssetExportSession(asset: asset, 
        presetName: AVAssetExportPresetAppleM4A) else{return}

        // Creating new output File url and removing it if already exists.
        let furl = createUrlInAppDD("trimmedAudio.m4a") //Custom Function
        removeFileIfExists(fileURL: furl) //Custom Function

        exportSession.outputURL = furl
        exportSession.outputFileType = AVFileType.m4a

        let start: CMTime = CMTimeMakeWithSeconds(startTime, preferredTimescale: asset.duration.timescale)
        let stop: CMTime = CMTimeMakeWithSeconds(stopTime, preferredTimescale: asset.duration.timescale)
        let range: CMTimeRange = CMTimeRangeFromTimeToTime(start: start, end: stop)
        exportSession.timeRange = range

        exportSession.exportAsynchronously(completionHandler: {

            switch exportSession.status {
            case .failed:
                print("Export failed: \(exportSession.error!.localizedDescription)")
            case .cancelled:
                print("Export canceled")
            default:
                print("Successfully trimmed audio")
                DispatchQueue.main.async(execute: {
                    finished(furl)
                })
            }
        })
    }
}

You can use it for video trimming as well. For Video trimming replace the value of export session as bellow:

guard let exportSession = AVAssetExportSession(asset: asset, presetName: AVAssetExportPresetPassthrough) else{return}

and filetype to mp4

exportSession.outputFileType = AVFileType.mp4

Him bhatt
  • 49
  • 5
2

Here is a sample code which trim audio file from starting & ending offset and save it back. Please check this iOS Audio Trimming.

// Path of your source audio file
NSString *strInputFilePath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"abc.mp3"];
NSURL *audioFileInput = [NSURL fileURLWithPath:strInputFilePath];

// Path of your destination save audio file
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES);
    NSString *libraryCachesDirectory = [paths objectAtIndex:0];
    libraryCachesDirectory = [libraryCachesDirectory stringByAppendingPathComponent:@"Caches"];

NSString *strOutputFilePath = [NSString stringWithFormat:@"%@%@",libraryCachesDirectory,@"/abc.mp4"];
NSURL *audioFileOutput = [NSURL fileURLWithPath:strOutputFilePath];

if (!audioFileInput || !audioFileOutput)
{
    return NO;
}

[[NSFileManager defaultManager] removeItemAtURL:audioFileOutput error:NULL];
AVAsset *asset = [AVAsset assetWithURL:audioFileInput];

AVAssetExportSession *exportSession = [AVAssetExportSession exportSessionWithAsset:asset presetName:AVAssetExportPresetAppleM4A];

if (exportSession == nil)
{
    return NO;
}
float startTrimTime = 0; 
float endTrimTime = 5;

CMTime startTime = CMTimeMake((int)(floor(startTrimTime * 100)), 100);
CMTime stopTime = CMTimeMake((int)(ceil(endTrimTime * 100)), 100);
CMTimeRange exportTimeRange = CMTimeRangeFromTimeToTime(startTime, stopTime);

exportSession.outputURL = audioFileOutput;
exportSession.outputFileType = AVFileTypeAppleM4A;
exportSession.timeRange = exportTimeRange;

[exportSession exportAsynchronouslyWithCompletionHandler:^
{
    if (AVAssetExportSessionStatusCompleted == exportSession.status)
    {
        NSLog(@"Success!");
    }
    else if (AVAssetExportSessionStatusFailed == exportSession.status)
    {
        NSLog(@"failed");
    }
}];
Community
  • 1
  • 1
Rishi
  • 37
  • 1