在macOS上播放声音

时间:2016-12-10 13:07:31

标签: swift macos audio avaudiosession

我喜欢在我的应用中播放声音。我发现了很多例子,也可以在Swift 3上编译和运行它们。但是它们总是用于iOS。当在我的应用程序中使用此代码时,AVAudioSession保持未定义。我需要做什么? OSX有什么不同的东西吗?

import AVFoundation
...
    var audioPlayer = AVAudioPlayer()
    func PlaySound( ) {
        let alertSound = URL(fileURLWithPath: Bundle.main.path(forResource: "Sound", ofType: "mp3")!)
        do {
            try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback)
        } catch _ {
        }
        do {
            try AVAudioSession.sharedInstance().setActive(true)
        } catch _ {
        }
        do {
            audioPlayer = try AVAudioPlayer(contentsOf: alertSound)
        } catch _{
        }
        audioPlayer.prepareToPlay()
        audioPlayer.play()
    }

3 个答案:

答案 0 :(得分:6)

Swift 3/4 / 4.2 / 5 - 最简单的解决方案:

NSSound(named: "customSound")?.play()

答案 1 :(得分:5)

我将以下函数与Swift 3和Cocoa项目结合使用。

import AVFoundation

func playSound(file:String, ext:String) -> Void {
    let url = Bundle.main.url(forResource: file, withExtension: ext)!
    do {
        let player = try AVAudioPlayer(contentsOf: url)
        player.prepareToPlay()
        player.play()
    } catch let error {
        print(error.localizedDescription)
    }
}

//用法//

playSound(file: "sound", ext: "caf") // where the file name is sound.caf.

确保在Xcode项目中选择音频文件时,目标成员资格复选框已打开。

答案 2 :(得分:0)

El Tomato答案的修改版本, 这是我经常用于声音的Swift 4.2类:

用法:

    /// EXAMPLE 1
    //calling this will create a "bop.m4a" player in memory, and, play it immediately
    MakeSound.shared.playSound("bop.m4a")
    //calling it a second time has a lot less overhead because the player is already in memory
    MakeSound.shared.playSound("bop.m4a")

    ///EXAMPLE 2
    //simply calls the above many times
    MakeSound.shared.playSound(["bop.m4a", "beep.m4a", "bong.m4a"])

    // EXAMPLE 3
    //registers a shorthand, for quick calling
    MakeSound.shared.registerSound(fileName: "bop", fileExtension: "m4a", shortHand: "b")
    //plays using the shorthand, mostly handy because you define the actual file once,
    //and can change the one line of code without having to change every reference
    MakeSound.shared.playSound("b")

和班级

class MakeSound {
private var players = [String : AVAudioPlayer]()
static var shared = MakeSound()

func playSound(fileName: String, fileExtension: String) {
    if registerSound(fileName: fileName, fileExtension: fileExtension, shortHand: fileName+"."+fileExtension) {
        playSound(fileName+"."+fileExtension)
    }
}

//thought about naming this "playsoundS", but i like it with the same name, makes it easier to type
func playSound(_ shortHands : [String]){
    for sh in shortHands{
        playSound(sh)
    }
}

///playSound("shorthand") OR playSound("mySound.mp3")
func playSound(_ shortHand : String) {
    if let player = players[shortHand]  {
        player.prepareToPlay()
        player.play()
    } else {
        if shortHand.contains(".") {
            //going to assume that coder will not send "." as a filepath
            //also going to assume that coder will not send "xyz." as filepath
            var comp = shortHand.components(separatedBy: ".")
            let ext = comp.last!
            comp.removeLast()
            if registerSound(fileName: comp.joined(separator: "."), fileExtension: ext, shortHand: shortHand) {
                playSound(shortHand)
            }
        } else {
            print("Sound request sent to makesound, no such shorthand, not a valid filename either.")
        }
    }
}

///registers a sound with makeSound, and returns a bool based on the success
@discardableResult func registerSound(fileName : String, fileExtension: String, shortHand: String) -> Bool {
    guard let url = Bundle.main.url(forResource: fileName, withExtension: fileExtension) else {
        print("Unable to register sound: \(shortHand). Filepath not valid.")
        return false
    }
    do {
        let player = try AVAudioPlayer(contentsOf: url)
        players[shortHand] = player
    } catch let error {
        print("Audioplayer \"\(shortHand)\" unable to initialize:\n" + error.localizedDescription)
        return false
    }
    return true
}

}

现在,我承认NSSound是迄今为止最简单,最直接的方法,但是,我们中有些人更喜欢AVFoundation,因为我们拥有更多的控制权。 (讽刺的是,此类控件已在我的课程中删除)