Search code examples
iosaudiocropseektrim

iOS Audio Trimming


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.


Solution

  • 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.