Смешайте два аудио файла в быстром с другой точки входа - PullRequest
0 голосов
/ 16 ноября 2018

Я пытаюсь смешать два аудио файла в быстрых 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)
      }
    }
  }

Ответы [ 3 ]

0 голосов
/ 16 ноября 2018

Вы можете добавить другой 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))

Вы также можете подключить sampleDelay AU между узлом 2 и микшером. Это облегчает работу без программирования вручную.

0 голосов
/ 19 ноября 2018

Вы должны использовать 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)
}
0 голосов
/ 16 ноября 2018

У меня лично нет опыта работы с AVAudioEngine или AVAudioMixerNode, однако вы можете сделать это с 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()
}
...