AVAudioengine воспроизведение / зацикливание звука, несколько кнопок

У меня есть эта кнопка для воспроизведения и зацикливания wav. Но что, если у меня есть вторая кнопка с другой петлей? Я хочу, чтобы этот второй цикл начал воспроизводиться после нажатия, однако первый цикл должен закончить свой «раунд». И наоборот (воспроизведите и зациклите второй цикл, нажмите кнопку первого цикла, и он вступит во владение)

 @IBAction func playButtonTapped(_ sender: Any) {



    guard let filePath: String = Bundle.main.path(forResource: "25loop110", ofType: "wav") else{ return }
          print("\(filePath)")
          let fileURL: URL = URL(fileURLWithPath: filePath)
          guard




              let audioFile = try? AVAudioFile(forReading: fileURL) else{ return }

          let audioFormat = audioFile.processingFormat
          let audioFrameCount = UInt32(audioFile.length)
          guard let audioFileBuffer = AVAudioPCMBuffer(pcmFormat: audioFormat, frameCapacity: audioFrameCount)  else{ return }
          do{
              try audioFile.read(into: audioFileBuffer)

              timeShift.rate = adjustedBpm/bpm
              playerNode.scheduleFile(audioFile, at: nil, completionHandler: nil)


          } catch{
              print("over")
          }

          try? audioEngine.start()
          playerNode.play()
          playerNode.scheduleBuffer(audioFileBuffer, at: nil, options:.loops,completionHandler: nil)

    }

person user1737746    schedule 09.02.2020    source источник


Ответы (2)


Вы можете справиться с таким поведением, используя параметр completionHandler в .scheduleBuffer.

Например, вы можете сделать что-то вроде этого:

var nextAudioFilePath: String  
var isPlaying: Bool = false

@IBAction func playLoopA() {  
   guard let path = Bundle.main.path(forResource: "audioFileA", ofType: "wav") else { return }  
   nextAudioFilePath = path  
   guard !isPlaying else { return }  
   play()
}  

@IBAction func playLoopB() {  
   guard let path = Bundle.main.path(forResource: "audioFileB", ofType: "wav") else { return }  
   nextAudioFilePath = path  
   guard !isPlaying else { return }  
   play()
}  

private func play() {  
   let fileURL = URL(fileURLWithPath: nextAudioFilePath)  
   ...  
   playerNode.scheduleBuffer(audioFileBuffer, at: nil, options: [], completionHandler: { [weak self] in   
      self?.play()
   })
}  
person Robin Schmidt    schedule 09.02.2020
comment
Спасибо, Робин, я разберусь с этим !! - person user1737746; 09.02.2020
comment
не могли бы вы объяснить, где я могу разместить разные URL-адреса wav в этом случае? - person user1737746; 09.02.2020
comment
Добро пожаловать :-) не забывайте принять ответ, если он решил вашу проблему ;-) - person Robin Schmidt; 09.02.2020
comment
У меня есть последний вопрос, если вы не возражаете. Это неправильно, но я не знаю, как это изменить: - person user1737746; 09.02.2020
comment
private func play () {guard let filePath: String = Bundle.main.path (forResource: 25loop110, ofType: wav) else {return} print ((filePath)) let fileURL = URL (fileURLWithPath: nextAudioFilePath) guard let audioFile = try ? AVAudioFile (forReading: fileURL) else {return} - person user1737746; 09.02.2020
comment
Вам нужно удалить первую строку guard let filePath: String = Bundle.main.path(forResource: "25loop110", ofType: "wav") else{ return }, потому что filePath теперь установлен извне. Но что именно не так? - person Robin Schmidt; 09.02.2020
comment
ах, ладно, я проверю это и посмотрю, что будет. - person user1737746; 09.02.2020
comment
Ах, отлично !! Ты действительно спас мне день. Спасибо, Робин !! - person user1737746; 09.02.2020

Я тоже нашел такое решение:

playerNode.scheduleBuffer(audioFileBuffer, at: nil, options:[.interruptsAtLoop, .loops],completionHandler: nil)
person user1737746    schedule 09.02.2020