【问题标题】:Using multiple AKPlayers for multiple audio files playback使用多个 AKPlayers 播放多个音频文件
【发布时间】:2018-08-10 07:16:43
【问题描述】:

我正在尝试使用 AudioKit 的 AKPlayer 同步播放 4 个 mp3 文件,并且非常成功。不过,作为我 Swift 研究的一部分,我想使用数组(或者我还没有学过的东西)来简化我的代码,因为我觉得我的代码中有一些多余的东西,只是将玩家代码复制了四次。下面是我写的代码:

    let file1 = try? AKAudioFile(readFileName: "mixing_1_vocal.mp3")
    let file2 = try? AKAudioFile(readFileName: "mixing_2_drums.mp3")
    let file3 = try? AKAudioFile(readFileName: "mixing_3_synth.mp3")
    let file4 = try? AKAudioFile(readFileName: "mixing_4_bass.mp3")


    let player1 = AKPlayer(audioFile: file1!)
    let player2 = AKPlayer(audioFile: file2!)
    let player3 = AKPlayer(audioFile: file3!)
    let player4 = AKPlayer(audioFile: file4!)
    let startTime = AVAudioTime.now() + 0.25

    let mixer = AKMixer()
    player1 >>> mixer
    player2 >>> mixer
    player3 >>> mixer
    player4 >>> mixer

    player1.isLooping = true
    player1.buffering = .always
    player2.isLooping = true
    player2.buffering = .always
    player3.isLooping = true
    player3.buffering = .always
    player4.isLooping = true
    player4.buffering = .always

    AudioKit.output = mixer

    try? AudioKit.start()
    player1.start(at: startTime)
    player2.start(at: startTime)
    player3.start(at: startTime)
    player4.start(at: startTime)

就是这样!有四个不同的轨道(单独的乐器),它们应该同时播放,无限循环。如果有人可以帮助我改进我的代码,那将非常有帮助。是否有更好的方法来执行相同的工作?

【问题讨论】:

    标签: swift audiokit


    【解决方案1】:

    这是一个非常开放的问题,但这里有一个适用于 iOS 的 ViewController 示例。

    class ViewController: UIViewController {
    
        let mixer = AKMixer()
        let players: [AKPlayer] = {
            do {
                let filenames = ["mixing_1_vocal.mp3",
                                 "mixing_2_drums.mp3",
                                 "mixing_3_synth.mp3",
                                 "mixing_4_bass.mp3"]
    
                return try filenames.map { AKPlayer(audioFile: try AKAudioFile(readFileName: $0)) }
            } catch {
                fatalError()
            }
        }()
    
    
        override func viewDidLoad() {
            super.viewDidLoad()
    
            makeConnections()
            startAudioEngine()
            preparePlayers()
            startPlayers()
        }
    
        func makeConnections() {
            players.forEach { $0 >>> mixer }
            AudioKit.output = mixer
        }
    
        func startAudioEngine() {
            do {
                try AudioKit.start()
            } catch {
                print(error)
                fatalError()
            }
        }
    
        func preparePlayers() {
            players.forEach { player in
                player.isLooping = true
                player.buffering = .always
                player.prepare()
            }
        }
    
        func startPlayers() {
            let startTime = AVAudioTime.now() + 0.25
            players.forEach { $0.start(at: startTime) }
        }
    
    }
    

    关键点:

    使用do {try expression} catch { error },而不是try? expression。虽然忽略错误很方便,但它会很快让您陷入困境。

    MapforEach,map 对于处理数组至关重要。请注意文件名数组如何转换为 AKPlayers 数组。相关的简写参数名称:players.forEach { player in player.play() }players.forEach { $0.play() } 相同。还有相关的,地图重新抛出,所以你可以在地图的封闭内尝试。

    使用闭包进行封装。使用立即评估的闭包定义了 player 变量。另一种方法是必须在 init 上创建这个数组,然后再填充它。

    最后,尽可能将逻辑分解为函数。它使您的代码更具可读性,并且更易于维护。

    【讨论】:

      猜你喜欢
      • 2020-02-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-10-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多