1 Reply
      Latest reply on Jul 26, 2019 2:19 AM by stef.b
      stef.b Level 1 Level 1 (0 points)

        My code is supposed to play a file from an AVAudioPlayerNode through my custom Audio Unit (V3) and render offline to an output file using manualRenderingMode. This seems to work fine if the file is mono or stereo, but as soon as more than tow channels are present, it stops working. The output file has the correct number of channels and the expected length, but the content is silence. I tried installing a tap on the output of my audio unit and writing to the output file from there, and this works fine. However, I need this to work as intended and write to file AVAudioEngine.renderOffline.


        
Below, I am posting a sample code that exhibits the same behaviour but has a simpler configuration: the engine operates offline and has only a file player node connected to the mainMixerNode. The output is saved to a file. Again, this code works fine for mono or stereo, but generates a silent output file in case of a 4-channels input file. 


        
 

        
 

        public func renderOffline(from inputUrl: URL, to outputUrl: URL) {
                let engine         = AVAudioEngine()
                let player         = AVAudioPlayerNode()
                let frameCount     : AVAudioFrameCount = 1024
                var numFrames      : AVAudioFrameCount
                var framesToRender : AVAudioFrameCount = 0
                var result         : AVAudioEngineManualRenderingStatus
        

                guard let inFile = try? AVAudioFile(forReading: inputUrl),
                      let outFile = try? AVAudioFile(forWriting: outputUrl, settings: inFile.processingFormat.settings),
                      let buffer = AVAudioPCMBuffer(pcmFormat: inFile.processingFormat, frameCapacity: frameCount) else {
                        return
                }
        

                engine.attach(player)
                engine.connect(player, to: engine.mainMixerNode, format: inFile.processingFormat)
               
                do {
                    try engine.enableManualRenderingMode(.offline, format: inFile.processingFormat, maximumFrameCount: frameCount)
                    try engine.start()
                } catch {
                    return
                }
        

                let fileLength = AVAudioFrameCount(inFile.length)
               
                player.scheduleFile(inFile, at: nil, completionHandler: nil)
                player.prepare(withFrameCount: fileLength)
                player.play()
               
                while engine.manualRenderingSampleTime < inFile.length {
                    numFrames = fileLength - frameCount
                    framesToRender = min(buffer.frameCapacity, numFrames)
                   
                    do {
                        result = try engine.renderOffline(framesToRender, to: buffer)
                        if result == .success {
                            try outFile.write(from: buffer)
                        }
                    } catch {
                        break
                    }
                }
               
                player.stop()
                engine.stop()
            }