【问题标题】:Mix two audio files in swift with different start point entry使用不同的起点条目快速混合两个音频文件
【发布时间】:2018-11-16 15:48:52
【问题描述】:

我正在尝试在 swift AVFoundations 中混合两个音频文件。我有一个混合两个音频并同时播放它们的解决方案。我真正想要的是在一段时间后开始第二个音频。例如,音频 1 播放,然后第二个音频在 10(给定时间)秒后开始播放。任何帮助表示赞赏。提前致谢。

private var audioFiles: Array<String>
private var audioEngine: AVAudioEngine = AVAudioEngine()
private var mixer: AVAudioMixerNode = AVAudioMixerNode()

func Play() {
    // do work in a background thread
    DispatchQueue.global(qos: .background).async {
      self.audioEngine.attach(self.mixer)
      self.audioEngine.connect(self.mixer, to: self.audioEngine.outputNode, format: nil)
      // !important - start the engine *before* setting up the player nodes
      try! self.audioEngine.start()

      let fileManager = FileManager.default
      for audioFile in self.audioFiles {
        // Create and attach the audioPlayer node for this file
        let audioPlayer = AVAudioPlayerNode()
        self.audioEngine.attach(audioPlayer)
        // Notice the output is the mixer in this case
        self.audioEngine.connect(audioPlayer, to: self.mixer, format: nil)
        let fileUrl = NSURL.init(fileURLWithPath: fileName.removingPercentEncoding!)
        var file : AVAudioFile

        // We should probably check if the file exists here ¯\_(ツ)_/¯
        try! AVAudioFile.init(forReading: fileUrl.absoluteURL!)

        audioPlayer.scheduleFile(file, at: nil, completionHandler: nil)
        audioPlayer.play(at: nil)
      }
    }
  }

【问题讨论】:

    标签: ios swift cocoa cocoa-touch avfoundation


    【解决方案1】:

    你应该使用scheduleSegment

    func scheduleWithOffset(_ offset: TimeInterval) {
    
        let samplerate1 = file1.processingFormat.sampleRate
        player1.scheduleSegment(file1,
                                startingFrame: 0,
                                frameCount: AVAudioFrameCount(file1.length),
                                at: AVAudioTime(sampleTime: 0, atRate: samplerate1))
    
        let samplerate2 = file2.processingFormat.sampleRate
        player2.scheduleSegment(file2,
                                startingFrame: 0,
                                frameCount: AVAudioFrameCount(file2.length),
                                at: AVAudioTime(sampleTime: AVAudioFramePosition(offset * samplerate2), atRate: samplerate2))
    
        //This can take an indeterminate amount of time, so both files should be prepared before either starts.
        player1.prepare(withFrameCount: 8192)
        player2.prepare(withFrameCount: 8192)
    
        // Start the files at common time slightly in the future to ensure a synchronous start.
        let hostTimeNow = mach_absolute_time()
        let hostTimeFuture = hostTimeNow + AVAudioTime.hostTime(forSeconds: 0.2);
        let startTime = AVAudioTime(hostTime: hostTimeFuture)
    
        player1.play(at: startTime)
        player2.play(at: startTime)
    }
    

    【讨论】:

      【解决方案2】:

      我个人没有使用AVAudioEngineAVAudioMixerNode 的经验,但是,您可以使用Timer 来做到这一点。

      您当前拥有audioPlayer.play(at: nil),但是,它始终会在建立此播放器后立即播放。我会做或尝试做的是为此应用某种计时器。

      var timeAfter = 10
      var timer = NSTimer.scheduledTimerWithInterval(timeAfter, target: self, selector: #selector(playAudio), userInfo: audioPlayer, repeats: false)
      

      将取代

      audioPlayer.play(at: nil)
      

      然后你会添加定时器的功能来播放音频。

      func playAudio(timer:NSTimer){
        var audioPlayer = timer.userInfo as AVAudioPlayerNode
        audioPlayer.play()
      }
      

      【讨论】:

        【解决方案3】:

        你可以添加另一个 playerNode 到混音器,然后像这样延迟播放:

            let audioPlayer2 = AVAudioPlayerNode()
            self.audioEngine.attach(audioPlayer2)
            self.audioEngine.connect(audioPlayer2, to: self.mixer, format: nil)
            var file2 : AVAudioFile = try! AVAudioFile.init(forReading: fileUrl2!)
            func delayTime(_ delayTime : TimeInterval) -> AVAudioTime{
                let  outputFormat = audioPlayer2.outputFormat(forBus: 0)
                let  startSampleTime = (audioPlayer2.lastRenderTime ?? AVAudioTime()).sampleTime +  Int64(Double(delayTime) * outputFormat.sampleRate);
                return  AVAudioTime(sampleTime: startSampleTime, atRate: outputFormat.sampleRate)
            }
            audioPlayer2.scheduleFile(file2, at: nil, completionHandler: nil)
            audioPlayer2.play(at: delayTime(3.0))
        

        您还可以在 node2 和混音器之间挂钩 sampleDelay AU。这让事情变得更容易,无需手动编程。

        【讨论】:

          猜你喜欢
          • 2012-03-02
          • 1970-01-01
          • 1970-01-01
          • 2021-03-02
          • 1970-01-01
          • 1970-01-01
          • 2016-10-19
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多