歌曲重复时如何循环播放没有延迟/延迟的背景音乐(无缝)

时间:2017-12-02 08:20:57

标签: swift xcode sprite-kit avfoundation

我正在尝试制作一个带有背景音乐的游戏。我在Adobe Audition中制作了歌曲文件(类似于大胆),当我在Adobe Audition的循环中播放它时,它会循环我想要它。

但是当我在Xcode中播放它时,它在循环之间有一个滞后。我正在使用AVFoundations进行声音播放。

我到处搜索但我无法找到问题的解决方案。

有没有办法可以循环播放音频文件而不会有任何滞后? (我相信它被称为"无缝循环")

这是代码:

class GameScene: SKScene {
...// Other Code

var ButtonAudio = URL(fileURLWithPath: Bundle.main.path(forResource: "Gamescene(new)", ofType: "mp3")!)
var ButtonAudioPlayer = AVAudioPlayer()

... //Other Code

}

当我打电话时:

 override func didMove(to view: SKView) {

    ...//Code

    ButtonAudioPlayer = try! AVAudioPlayer(contentsOf: ButtonAudio, fileTypeHint: nil)
    ButtonAudioPlayer.numberOfLoops = -1
    ButtonAudioPlayer.prepareToPlay()
    ButtonAudioPlayer.play()

    ...//More Code
    }

有人可以帮我解决这个问题吗?

提前谢谢!

2 个答案:

答案 0 :(得分:2)

您可以使用AVPlayerLooperAVQueuePlayer来执行此操作。

import UIKit
import AVFoundation

class ViewController: UIViewController {

    var queuePlayer = AVQueuePlayer()
    var playerLooper: AVPlayerLooper?

    override func viewDidLoad() {
        super.viewDidLoad()

        guard let url = Bundle.main.url(forResource: "Gamescene(new)", withExtension: "mp3") else { return }
        let playerItem = AVPlayerItem(asset: AVAsset(url: url))
        playerLooper = AVPlayerLooper(player: queuePlayer, templateItem: playerItem)
        queuePlayer.play()
    }
}

答案 1 :(得分:0)

@dave234提出的解决方案仅在iOS> 10中有效。由于我需要在iOS> 9中进行无缝播放,所以我做了一些不同的事情:

  1. 我创建了AVPlayer,而不是AVQueuePlayer,并立即向队列添加了两个相同的旋律。
  2. 接下来,我听了倒数第二首旋律。
  3. 触发监听器时,我在最后一个队列之后向队列添加了另一个类似的记录。

事实上,为了避免延迟,我总是播放倒数第二张的唱片。

我的代码:

var player: AVQueuePlayer?

override func viewDidLoad() {
    super.viewDidLoad()

    if let path = Bundle.main.path(forResource: "music_file", ofType: "mp3") {
        player = createPlayer(url: URL(fileURLWithPath: path))
    }
}

func createPlayer(url: URL) -> AVQueuePlayer {
    let player = AVQueuePlayer(items: [AVPlayerItem(url: url), AVPlayerItem(url: url)])
    loopPlayer(playerItem: player.items()[player.items().count - 2])
    return player
}

func loopPlayer(playerItem: AVPlayerItem) {
    NotificationCenter.default.addObserver(forName: .AVPlayerItemDidPlayToEndTime, object: playerItem, queue: .main) { _ in
        if let player = self.player, let url = (playerItem.asset as? AVURLAsset)?.url {
            player.insert(AVPlayerItem(url: url), after: player.items()[player.items().count - 1])
            self.loopPlayer(playerItem: player.items()[player.items().count - 2])
        }
    }
}