简体   繁体   English

如何使用AVAudioPlayerNode从资产目录中播放声音?

[英]How can I play a sound from the asset catalog using AVAudioPlayerNode?

I'm trying to use an AVAudioPlayerNode to play sounds from the Assets.xcassets asset catalog, but I can't figure out how to do it. 我正在尝试使用AVAudioPlayerNode来播放Assets.xcassets资产目录中的声音,但我无法弄清楚如何去做。

I've been using AVAudioPlayer , which can be initialized with an NSDataAsset like this: 我一直在使用AVAudioPlayer ,它可以用这样的NSDataAsset初始化:

let sound = NSDataAsset(name: "beep")!
do {
    let player = try AVAudioPlayer(data: sound.data, fileTypeHint: AVFileTypeWAVE)
    player.prepareToPlay()
    player.play()
} catch {
    print("Failed to create AVAudioPlayer")
}

I want to use an AVAudioPlayerNode instead (for pitch shifting and other reasons). 我想改用AVAudioPlayerNode (用于音高变换等原因)。 I can create the engine and hook up the node OK: 我可以创建引擎并连接节点OK:

var engine = AVAudioEngine()
func playSound(named name: String) {
    let mixer = engine.mainMixerNode
    let playerNode = AVAudioPlayerNode()
    engine.attach(playerNode)
    engine.connect(playerNode, to: mixer, format: mixer.outputFormat(forBus: 0))

    // play the file (this is what I don't know how to do)
}

It looks like the method to use for playing the file is playerNode.scheduleFile() . 看起来用于播放文件的方法是playerNode.scheduleFile() It takes an AVAudioFile , so I thought I'd try to make one. 它需要一个AVAudioFile ,所以我想我会尝试制作一个。 But the initializer for AVAudioFile wants a URL. 但是AVAudioFile的初始化程序需要一个URL。 As far as I can tell, assets in the asset catalog are not available by URL. 据我所知,资产目录中的资产不能通过URL获得。 I can get the data directly using NSDataAsset , but there doesn't seem to be any way to use it to populate an AVAudioFile . 我可以使用NSDataAsset直接获取数据,但似乎没有任何方法可以使用它来填充AVAudioFile

Is it possible to play sounds from the asset catalog with an AVAudioPlayerNode ? 是否可以使用AVAudioPlayerNode播放资产目录中的声音? And if so, how? 如果是这样,怎么样?

OK so your problem is that you would like to get a URL from a file in your Asset catalog right? 好的,你的问题是你想从资产目录中的文件中获取一个URL吗?

I've looked around but only found this answer 我环顾四周但却发现了这个答案

As it says 正如它所说

It basically just gets image from assets, saves its data to disk and return file URL 它基本上只是从资产中获取图像,将其数据保存到磁盘并返回文件URL

You should probably change it to look for MP3 files (or WAV or whatever you prefer, maybe that could be an input parameter) 您应该更改它以查找MP3文件(或WAV或您喜欢的任何内容,也许这可能是输入参数)

So you could end up with something like: 所以你最终会得到类似的东西:

enum SoundType: String {
    case mp3 = "mp3"
    case wav = "wav"
}

class AssetExtractor {

    static func createLocalUrl(forSoundNamed name: String, ofType type: SoundType = .mp3) -> URL? {

        let fileManager = FileManager.default
        let cacheDirectory = fileManager.urls(for: .cachesDirectory, in: .userDomainMask)[0]
        let url = cacheDirectory.appendingPathComponent("\(name).\(type)")

        guard fileManager.fileExists(atPath: url.path) else {
            guard
                let image = UIImage(named: name),
                let data = UIImagePNGRepresentation(image)
            else { return nil }

            fileManager.createFile(atPath: url.path, contents: data, attributes: nil)
            return url
        }
        return url
    }
}

Maybe a bit far fetched but I haven't found any other options. 也许有点牵强,但我还没有找到任何其他选择。

Hope that helps you. 希望对你有所帮助。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM