iOS: trimming audio files with Swift

Swift Language

iOS: trimming audio files

I’ve written about how to record audio on iOS using Swift.
But, how do you trim the recording?

Introduction

Table of Contents

One way to trim an audio file is to use AVFoundation’s AVAssetExportSession. You create an export session instance, set its parameters, and then tell it to export the asset (your audio file) according to those parameters.

In the recorder project, I saved the URL of the recording in the soundFileURL instance variable. To use AVAssetExportSession we need to create an AVAsset from it. Here is a simple action that creates the asset and then call the export function I will discuss next.

Now to define the export func.

You create the exporter from your asset and desired file format. Here I’m using the Apple lossless format.
Then I set the exporter’s outputURL property to a file URL in the documents directory. This will be the location of the trimmed audio file.

I create a core media time range using CMTimeRangeFromTimeToTime that specifies the time offsets for the beginning and ending for the trimmed file. Here I just hard code the values, but of course you’d use a slider or a waveform view to choose the time boundaries.

While you’re there, you can also specify an AVMutableAudioMix for the volume. You can even specify a volume ramp.

Once the exporter’s properties are set, you call exportAsynchronouslyWithCompletionHandler to do the actual work. You can check the status of the export in the completion handler.

Or using Swift 4 syntax:

Groovy, huh?

Summary

Table of Contents

To trim an audio (or video) file, use AVFoundation’s AVAssetExportSession.

Resources

Table of Contents

16 thoughts on “iOS: trimming audio files with Swift”

  1. Thanks for good example.

    In the next post, could you make an example about Streaming music with Swift ?

    I’m start to learn swift and build up my first app about Streaming Music Online. Then i get stuck in the process to get the duration of mp3 file from URL, still looking for the solution for it.

    Regards,

    1. You should play your streaming audio with AVPlayer. Instantiate AVPlayer with new player item, call play() func and when AVPlayer actually starts playing (isPlating == true) you can grab duration of your mp3 file.
      Below is an extension to AVPlayer.

      extension AVPlayer {

      var isPlaying: Bool {
      return rate != 0 && error == nil
      }

      }

  2. Hi. You mentioned that we can use slider or a waveform view to choose the time boundaries. I have been searching for a tutorial about that for a week and i couldn’t find anything. Could you please explain that too? i would really appreciate it.

  3. Is it possible to change the pitch and rate in the method “exportAsset” ? If it is possible how should i do this?

    1. i m trying to trim an mp3 file that is locally saved.

      The code runs correctly as per my use case, let exportSession = AVAssetExportSession(asset: asset, presetName: AVAssetExportPresetPassthrough)

      exportSession?.outputFileType = AVFileTypeQuickTimeMovie

      I exported as the above formats.

      But i keep getting the exported outfile duration as zero
      Below is the code

  4. i m trying to trim an mp3 file that is locally saved.

    The code runs correctly as per my use case, let exportSession = AVAssetExportSession(asset: asset, presetName: AVAssetExportPresetPassthrough)

    exportSession?.outputFileType = AVFileTypeQuickTimeMovie

    I exported as the above formats.

    But i keep getting the exported outfile duration as zero
    Below is the code

    func exportAsset(asset:AVAsset, fileName:String) {

    // var audioUrl : URL = URL.init(string: “ipod-library://item/item.mp3?id=2928197610297287611”)!
    // var avAsset: AVAsset = AVAsset(url: audioUrl)

    let documentsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
    let trimmedSoundFileURL = documentsDirectory.appendingPathComponent(fileName)

    print(“saving to \(trimmedSoundFileURL.absoluteString)”)

    let filemanager = FileManager.default
    if filemanager.fileExists(atPath: trimmedSoundFileURL.absoluteString) {
    print(“sound exists”)
    }

    let exportSession = AVAssetExportSession(asset: asset, presetName: AVAssetExportPresetPassthrough)
    exportSession?.outputFileType = AVFileTypeQuickTimeMovie
    exportSession?.outputURL = trimmedSoundFileURL

    let duration = CMTimeGetSeconds(asset.duration)
    if (duration Void in
    if exportSession?.status == .completed {
    print(“AVAssetExportSessionStatusCompleted”)
    print(exportSession?.asset)
    // play trimmed song

    }
    else if exportSession?.status == .failed {
    // 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
    print(“AVAssetExportSessionStatusFailed”)
    }
    else {
    print(“Export Session Status: \(exportSession?.status)”)
    }

    })
    }

    func playTrimmedSong() {
    let url: URL = URL.init(string: “file:///var/mobile/Containers/Data/Application/B57F6319-9412-4238-900F-85CE0A4EB343/Documents/trimmed4.m4a”)!

    let avAsset: AVAsset = AVAsset(url: url)

    print(avAsset.duration.seconds)

    }
    </code

  5. Hello,
    I have an important voice memo recorded in 20171108 on my iphone. Unfortunally i didn’t save in Itunes or in iCloud
    Today 20171202 i trimmed this voice memo
    Trimmed version (20171202) look like overwrite original version (20171108)
    I used application ibrowse to find voice memo file, but in the folder Recording i just have trimmed version not original version.

    I try to use assetmanifest.plist but i’m not confortable with code and function you exposed.
    Could you please help to fix my issue?

    1. Look at the first example:

      As you see, I’m specifying a new filename for the trimmed sound file.

  6. Hello,
    Thank you for quick reply.
    I’m a novice in code so i need your help.
    I need a procedure with step by step, could you help me please?
    Where i put this code? In which file?
    This code will be execute?

    Below is what i understood:
    1- In the forlder Recording add new file with this code:
    @IBAction
    func trim() {
    if let asset = AVAsset.assetWithURL(self.soundFileURL) as? AVAsset {
    exportAsset(asset, fileName: “20171108 195140.m4a”)
    }
    }
    2- 20171108 195140.m4a it’s a trimmed filename
    3- If i rename “20171108 195140.m4a” to “20171203_NewFileName.m4a” how i do the link between trimmed file and new file

    Can i share my files with you please?

    Thank you in advance

  7. Hi,
    I’m using AudioKit and range slider for trimming audio. The audio in counted samples. Range slider in CGFloat, and trimming in calculated in seconds. The problem I keep facing is that seconds in the slider don’t correspond the samples in the audio. Can you advise the right way if solving it? Or may be recommend a good library for it. Thanks in advance.

    Screenshot: https://ibb.co/jAyeT0

  8. When I try to pull the file and play it using MediaPlayer, it plays the full music. I checked the file and I’m pretty sure it’s the trimmed one that is saved. Please help.

    1. I just tried my example again and it does trim it. Try renaming it to make sure you’re using the right file.
      Of course, you have the code I’m using, so if you find a bug, let me know!

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.