Как воспроизвести звук из каталога ресурсов с помощью AVAudioPlayerNode?
Я пытаюсь использовать AVAudioPlayerNode
играть звуки из Assets.xcassets
Каталог активов, но я не могу понять, как это сделать.
Я использую 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")
}
Я хочу использовать AVAudioPlayerNode
вместо этого (для изменения высоты тона и других причин). Я могу создать движок и подключить узел ОК:
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)
}
Похоже, метод для воспроизведения файла playerNode.scheduleFile()
, Требуется AVAudioFile
Так что я подумал, что попробую сделать один. Но инициализатор для AVAudioFile
хочет URL. Насколько я могу судить, ресурсы в каталоге активов не доступны по URL. Я могу получить данные напрямую, используя NSDataAsset
, но, кажется, нет никакого способа использовать его для заполнения AVAudioFile
,
Можно ли воспроизводить звуки из каталога активов с AVAudioPlayerNode
? И если да, то как?
1 ответ
Итак, ваша проблема в том, что вы хотели бы получить URL
из файла в вашем каталоге активов не так ли?
Я посмотрел вокруг, но нашел только этот ответ
Как говорится
Он просто получает изображение из ресурсов, сохраняет свои данные на диск и возвращает URL файла
Вы, вероятно, должны изменить его, чтобы искать файлы MP3 (или WAV или что-то еще, возможно, это может быть входной параметр)
Таким образом, вы можете получить что-то вроде:
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
}
}
Возможно, немного надуманно, но я не нашел других вариантов.
Надеюсь, это поможет вам.