How to change the speed of an audio track (mp3)?

I have this theory that AVMutableComposition does not work without a video track. I'm trying to change the speed of an audio track (mp3) using the



func scaleTimeRange(_ timeRange: CMTimeRange, toDuration duration: CMTime)



function. Below is the code I have so far,



static func changeSpeed(audio: AVURLAsset, factor: Float64, outputURL: URL, completionHandler:@escaping ((_ success: Bool) -> Void)) {
            print(#function + " started: " + Date().description)
           
            guard factor > 0 else {
                DispatchQueue.main.async {
                    print(#function + ": Speed factor must be a positive value")
                    completionHandler(false)
                }
                return
            }
           
            guard let assetAudioTrack = audio.tracks(withMediaType: .audio).first else {
                DispatchQueue.main.async {
                    print(#function + ": No asset track found")
                    completionHandler(false)
                }
                return
            }
           
            let composition = AVMutableComposition()
           
            let audioTrack = composition.addMutableTrack(
                withMediaType: AVMediaType.audio,
                preferredTrackID: kCMPersistentTrackID_Invalid
            )
            do {
                try audioTrack?.insertTimeRange(
                    CMTimeRangeMake(start: CMTime.zero, duration: audio.duration),
                    of: assetAudioTrack,
                    at: CMTime.zero
                )
            } catch {
                DispatchQueue.main.async {
                    print(#function + ": Failed to add " + audio.url.absoluteString)
                    completionHandler(false)
                }
                return
            }
           
            let exporter = AVAssetExportSession(
                asset: composition,
                presetName: AVAssetExportPresetAppleM4A
            )
           
            exporter?.outputURL = outputURL
            exporter?.outputFileType = AVFileType.m4a
           
            audioTrack?.scaleTimeRange(CMTimeRange.init(start: CMTime.zero, end: audio.duration), toDuration: CMTimeMultiplyByFloat64(audio.duration, multiplier: 1/factor))
           
            exporter?.exportAsynchronously {
                if exporter?.status == .completed {
                    DispatchQueue.main.async {
                        completionHandler(true)
                        print(#function + " ended: " + Date().description)
                    }
                } else {
                    DispatchQueue.main.async {
                        completionHandler(false)
                        print(#function + " ended with error: " + Date().description)
    if let errorString = exporter?.error.debugDescription {
                            print(errorString)
                        }
                    }
                }
            }
        }


Above code fails with or without the *scaleTimeRange* function. That is why I'm thinking that AVMutableComposition will work only when there are video tracks.



I did play around a little by changing the preset and output file type. Below are my observations,



preset: AVAssetExportPresetAppleM4A

file type: AVFileType.m4a



Error Domain=AVFoundationErrorDomain Code=-11800 "The operation could

not be completed" UserInfo={NSLocalizedFailureReason=An unknown error

occurred (-12780), NSLocalizedDescription=The operation could not be

completed, NSUnderlyingError=0x281164960 {Error

Domain=NSOSStatusErrorDomain Code=-12780 "(null)"}}



preset: AVAssetExportPresetPassthrough

file type: AVFileType.m4a



Error Domain=AVFoundationErrorDomain Code=-11822 "Cannot Open"

UserInfo={NSLocalizedFailureReason=This media format is not

supported., NSLocalizedDescription=Cannot Open,

NSUnderlyingError=0x28178fc30 {Error Domain=NSOSStatusErrorDomain

Code=-16976 "(null)"}}



I printed the supported file types of AVAssetExportSession when the preset is AVAssetExportPresetPassthrough.



print(#function + ": Supported file types -> " + String.init(format: "%@", exporter?.supportedFileTypes ?? []))



Below is the output of the above. I can clearly see m4a in the list.



"com.apple.quicktime-movie",

"com.apple.m4a-audio",

"public.mpeg-4",

"com.apple.m4v-video",

"public.3gpp",

"org.3gpp.adaptive-multi-rate-audio",

"com.microsoft.waveform-audio",

"public.aiff-audio",

"public.aifc-audio",

"com.apple.coreaudio-format"



I need help to build a function that would change the speed of an audio track for me. The audio track could be an asset in the bundle or picked from the MPMediaPickerController.



Thanks!

How to change the speed of an audio track (mp3)?
 
 
Q