歌曲重复时如何在没有 lag/delay 的情况下循环播放背景音乐(无缝)
How to loop background music without lag/delay when song repeats (seamless)
我正在尝试制作一款背景音乐循环播放的游戏。我在 Adobe Audition(类似于 audacity)中制作了歌曲文件,当我在 Adobe Audition 中循环播放它时,它会按照我想要的方式循环播放。
然而,当我在 Xcode 中播放它时,它在循环之间有延迟。我正在使用 AVFoundations 播放声音。
我到处搜索,但找不到问题的解决方案。
有没有什么方法可以循环播放音频文件而中间没有任何滞后? (我相信它叫 "seamless looping" )
代码如下:
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
}
有人可以帮我解决这个问题吗?
提前致谢!
您可以使用 AVPlayerLooper and AVQueuePlayer 来执行此操作。
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()
}
}
@dave234提出的解决方案只适用于iOS>10。由于我需要在iOS>9中进行无缝播放,我做了一些不同的事情:
- 我创建了
AVQueuePlayer
而不是 AVPlayer
,并立即将两个相同的旋律添加到队列中。
- 接下来,我做了倒数第二个旋律的监听器。
- 监听器被触发时,我在上一条之后又在队列中添加了一条类似的记录。
其实为了避免耽误,我总是播放倒数第二条记录。
我的代码:
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])
}
}
}
我正在尝试制作一款背景音乐循环播放的游戏。我在 Adobe Audition(类似于 audacity)中制作了歌曲文件,当我在 Adobe Audition 中循环播放它时,它会按照我想要的方式循环播放。
然而,当我在 Xcode 中播放它时,它在循环之间有延迟。我正在使用 AVFoundations 播放声音。
我到处搜索,但找不到问题的解决方案。
有没有什么方法可以循环播放音频文件而中间没有任何滞后? (我相信它叫 "seamless looping" )
代码如下:
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
}
有人可以帮我解决这个问题吗?
提前致谢!
您可以使用 AVPlayerLooper and AVQueuePlayer 来执行此操作。
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()
}
}
@dave234提出的解决方案只适用于iOS>10。由于我需要在iOS>9中进行无缝播放,我做了一些不同的事情:
- 我创建了
AVQueuePlayer
而不是AVPlayer
,并立即将两个相同的旋律添加到队列中。 - 接下来,我做了倒数第二个旋律的监听器。
- 监听器被触发时,我在上一条之后又在队列中添加了一条类似的记录。
其实为了避免耽误,我总是播放倒数第二条记录。
我的代码:
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])
}
}
}