AVAudioPlayer 噼啪声和爆裂声

AVAudioPlayer crackles and pops

我有一个类似 Simon 的记忆游戏,其中播放一系列音调,用户尝试重复这些音调。问题是我时不时会听到可怕的爆裂声。它可能只在几个音符之后,也可能多达二十个。声音都是两秒长的wav文件。我循环播放 10 个播放器,以便 none 的声音被剪掉。 (我尝试了多达 50 个,但没有任何帮助。)我还尝试实施 audioPlayerDidFinishPlaying,以便在声音完成后我可以停止播放器,但这也没有帮助。最后,我添加了 prepareToPlay() - 遗憾的是,没有区别。

一个可能相关也可能不相关的有趣问题是,在大约 15 个音符的序列之后,音频一起停止工作。该应用程序继续正常运行,但没有任何声音。

这是代码的音频部分:

func playSound(_ soundID: Int) {
        var soundName = ""

        switch soundID {
        case 0:
            soundName = "beep1"
        case 1:
            soundName = "beep2"
        case 2:
            soundName = "beep3"
        case 3:
            soundName = "beep4"
        case 4:
            soundName = "swish3"
        default:
            soundName = "clank"
        }

        guard let url = Bundle.main.url(forResource: soundName, withExtension: "wav") else { return }

        do {
            buttonSound.insert(try AVAudioPlayer(contentsOf: url, fileTypeHint: AVFileType.wav.rawValue), at: playerIndex)
            buttonSound[playerIndex].prepareToPlay()
            buttonSound[playerIndex].delegate = self

            if playerIndex < 10 {
                buttonSound[playerIndex].play()
                playerIndex += 1
            } else {
                buttonSound[playerIndex].play()
                playerIndex = 0
            }

        } catch {
            // error
        }
    }

    func audioPlayerDidFinishPlaying(_ player: AVAudioPlayer, successfully flag: Bool) {
        if flag {
            player.stop()
        }
    }

/******** 更新 *********/

我将 AVAudioPlayer 创建移动到它自己的 class 基于一个过时的例子我 运行 在...某处。它解决了音频在 15 个音调后完全切断的问题,但是,裂纹和爆裂声仍然存在!我也试过重新录制声音,但没有成功。

这里是根据需要创建AVAudioPlayer的class:

import UIKit
import AVFoundation

private var players: [AVAudioPlayer] = []

class AVAudioPlayerPool: NSObject {

    class func playerWithURL(url: URL) -> AVAudioPlayer? {

        let availablePlayers = players.filter { (player) -> Bool in
            return player.isPlaying == false && player.url == url
        }

        if let playerToUse = availablePlayers.first {
            playerToUse.prepareToPlay()
            return playerToUse
        }

        do {
            let newPlayer = try AVAudioPlayer(contentsOf: url, fileTypeHint: AVFileType.wav.rawValue)
            players.append(newPlayer)
            newPlayer.prepareToPlay()
            return newPlayer

        } catch {
            return nil
        }
    }
}

播放声音很简单:

func playSound(_ soundID: Int) {
    var soundName = ""

    switch soundID {
    case 0:
        soundName = "tt1"
    case 1:
        soundName = "tt2"
    case 2:
        soundName = "tt3"
    case 3:
        soundName = "tt4"
    case 4:
        soundName = "swish3"
    default:
        soundName = "clank"
    }

    guard let url = Bundle.main.url(forResource: soundName, withExtension: "wav") else { return }
    let player = AVAudioPlayerPool.playerWithURL(url: url)
    player?.play()

}

如果有人有任何想法 - 即使这只是下一步,您也可以尝试...

在我看来,您的主要问题是声音加载是在应该播放声音本身的同一个函数内完成的。从概念上讲是错误的,为了能够尽可能快地播放声音,您应该在 "play" 函数之外一劳永逸地加载所有声音。该功能应该可以播放,仅此而已。

我们的团队刚刚遇到了这个问题。在我们的案例中,如果应用程序 运行 在连接了调试器的设备上,则 可以重现失真的声音错误。一旦我们将应用程序与调试器分离,噼啪声就会消失。 看起来这个问题首先出现在新的 Xcode 9.2 (9C40b) 中。

经过几个小时的实验,我会说问题是由我选择的声音引起的 - 一个大的、空心的、带有混响的方波合成器声音。我首先尝试降低可能有帮助的层次思维。接下来,我尝试了各种不同的声音,但都发出噼啪声。我认为这更多地与我分配球员的方式有关。一旦我解决了播放器问题,我就没想回去再尝试不同的声音。直到,我做了……而且它有效!