简体   繁体   中英

How to play a sound using Swift?

I would like to play a sound using Swift.

My code worked in Swift 1.0 but now it doesn't work anymore in Swift 2 or newer.

override func viewDidLoad() {
  super.viewDidLoad()

  let url:NSURL = NSBundle.mainBundle().URLForResource("soundName", withExtension: "mp3")!

  do { 
    player = try AVAudioPlayer(contentsOfURL: url, fileTypeHint: nil) 
  } catch _{
    return
  }

  bgMusic.numberOfLoops = 1
  bgMusic.prepareToPlay()

  if (Data.backgroundMenuPlayed == 0){
    player.play()
    Data.backgroundMenuPlayed = 1
  }
}

Most preferably you might want to use AVFoundation . It provides all the essentials for working with audiovisual media.

Update: Compatible with Swift 2 , Swift 3 and Swift 4 as suggested by some of you in the comments.


Swift 2.3

import AVFoundation

var player: AVAudioPlayer?

func playSound() {
    let url = NSBundle.mainBundle().URLForResource("soundName", withExtension: "mp3")!

    do {
        player = try AVAudioPlayer(contentsOfURL: url)
        guard let player = player else { return }

        player.prepareToPlay()
        player.play()

    } catch let error as NSError {
        print(error.description)
    }
}

Swift 3

import AVFoundation

var player: AVAudioPlayer?

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

    do {
        try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback)
        try AVAudioSession.sharedInstance().setActive(true)

        let player = try AVAudioPlayer(contentsOf: url)

        player.play()

    } catch let error {
        print(error.localizedDescription)
    }
}

Swift 4 (iOS 13 compatible)

import AVFoundation

var player: AVAudioPlayer?

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

    do {
        try AVAudioSession.sharedInstance().setCategory(.playback, mode: .default)            
        try AVAudioSession.sharedInstance().setActive(true)

        /* The following line is required for the player to work on iOS 11. Change the file type accordingly*/
        player = try AVAudioPlayer(contentsOf: url, fileTypeHint: AVFileType.mp3.rawValue)

        /* iOS 10 and earlier require the following line:
        player = try AVAudioPlayer(contentsOf: url, fileTypeHint: AVFileTypeMPEGLayer3) */

        guard let player = player else { return }

        player.play()

    } catch let error {
        print(error.localizedDescription)
    }
}

Make sure to change the name of your tune as well as the extension . The file needs to be properly imported ( Project Build Phases > Copy Bundle Resources ). You might want to place it in assets.xcassets for greater convenience.

For short sound files you might want to go for non-compressed audio formats such as .wav since they have the best quality and a low cpu impact. The higher disk-space consumption should not be a big deal for short sound files. The longer the files are, you might want to go for a compressed format such as .mp3 etc. pp. Check the compatible audio formats of CoreAudio .


Fun-fact: There are neat little libraries which make playing sounds even easier. :)
For example: SwiftySound

For Swift 3 :

import AVFoundation

/// **must** define instance variable outside, because .play() will deallocate AVAudioPlayer 
/// immediately and you won't hear a thing
var player: AVAudioPlayer?

func playSound() {
    guard let url = Bundle.main.url(forResource: "soundName", withExtension: "mp3") else {
        print("url not found")
        return
    }

    do {
        /// this codes for making this app ready to takeover the device audio
        try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback)
        try AVAudioSession.sharedInstance().setActive(true)

        /// change fileTypeHint according to the type of your audio file (you can omit this)

        player = try AVAudioPlayer(contentsOf: url, fileTypeHint: AVFileTypeMPEGLayer3)

        // no need for prepareToPlay because prepareToPlay is happen automatically when calling play()
        player!.play()
    } catch let error as NSError {
        print("error: \(error.localizedDescription)")
    }
}

The best practice for local assets is to put it inside assets.xcassets and you load the file like this :

func playSound() {
    guard let url = Bundle.main.url(forResource: "soundName", withExtension: "mp3") else {
        print("url not found")
        return
    }

    do {
        /// this codes for making this app ready to takeover the device audio
        try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback)
        try AVAudioSession.sharedInstance().setActive(true)

        /// change fileTypeHint according to the type of your audio file (you can omit this)

        /// for iOS 11 onward, use :
        player = try AVAudioPlayer(contentsOf: url, fileTypeHint: AVFileType.mp3.rawValue)

        /// else :
        /// player = try AVAudioPlayer(contentsOf: url, fileTypeHint: AVFileTypeMPEGLayer3)

        // no need for prepareToPlay because prepareToPlay is happen automatically when calling play()
        player!.play()
    } catch let error as NSError {
        print("error: \(error.localizedDescription)")
    }
}

Swift version: 5.4 and Above

import AVFoundation
var player: AVAudioPlayer?

func playSound() {
    guard let path = Bundle.main.path(forResource: "beep", ofType:"mp3") else {
        return }
    let url = URL(fileURLWithPath: path)

    do {
        player = try AVAudioPlayer(contentsOf: url)
        player?.play()
        
    } catch let error {
        print(error.localizedDescription)
    }
}

iOS 12 - Xcode 10 beta 6 - Swift 4.2

Use just 1 IBAction and point all the buttons to that 1 action.

import AVFoundation

var player = AVAudioPlayer()

@IBAction func notePressed(_ sender: UIButton) {
    print(sender.tag) // testing button pressed tag
    let path = Bundle.main.path(forResource: "note\(sender.tag)", ofType : "wav")!
    let url = URL(fileURLWithPath : path)
    do {
        player = try AVAudioPlayer(contentsOf: url)
        player.play()
    } catch {
        print ("There is an issue with this code!")
    }
}

If code doesn't generate any error, but you don't hear sound - create the player as an instance:

   static var player: AVAudioPlayer!

For me the first solution worked when I did this change :)

Swift 4, 4.2 and 5

Play audio from URL and from your project (Local File)

import UIKit
import AVFoundation

class ViewController: UIViewController{

var audioPlayer : AVPlayer!

override func viewDidLoad() {
        super.viewDidLoad()
// call what ever function you want.
    }

    private func playAudioFromURL() {
        guard let url = URL(string: "https://geekanddummy.com/wp-content/uploads/2014/01/coin-spin-light.mp3") else {
            print("error to get the mp3 file")
            return
        }
        do {
            audioPlayer = try AVPlayer(url: url as URL)
        } catch {
            print("audio file error")
        }
        audioPlayer?.play()
    }

    private func playAudioFromProject() {
        guard let url = Bundle.main.url(forResource: "azanMakkah2016", withExtension: "mp3") else {
            print("error to get the mp3 file")
            return
        }

        do {
            audioPlayer = try AVPlayer(url: url)
        } catch {
            print("audio file error")
        }
        audioPlayer?.play()
    }

}

Swift 3

import AVFoundation


var myAudio: AVAudioPlayer!

    let path = Bundle.main.path(forResource: "example", ofType: "mp3")!
    let url = URL(fileURLWithPath: path)
do {
    let sound = try AVAudioPlayer(contentsOf: url)
    myAudio = sound
    sound.play()
} catch {
    // 
}

//If you want to stop the sound, you should use its stop()method.if you try to stop a sound that doesn't exist your app will crash, so it's best to check that it exists.

if myAudio != nil {
    myAudio.stop()
    myAudio = nil
}

For Swift 5 " AVFoundation "\

Simple code without error handling to play audio from your local path

import AVFoundation
var audio:AVPlayer!

func stopAlarm() {
    // To pause or stop audio in swift 5 audio.stop() isn't working
    audio.pause()
}

func playAlarm() {
    // need to declare local path as url
    let url = Bundle.main.url(forResource: "Alarm", withExtension: "mp3")
    // now use declared path 'url' to initialize the player
    audio = AVPlayer.init(url: url!)
    // after initialization play audio its just like click on play button
    audio.play()
}

在此处输入图像描述

This is basic code to find and play an audio file in Swift.

Add your audio file to your Xcode and add the code below.

import AVFoundation

class ViewController: UIViewController {

   var audioPlayer = AVAudioPlayer() // declare globally

   override func viewDidLoad() {
        super.viewDidLoad()

        guard let sound = Bundle.main.path(forResource: "audiofilename", ofType: "mp3") else {
            print("Error getting the mp3 file from the main bundle.")
            return
        }
        do {
            audioPlayer = try AVAudioPlayer(contentsOf: URL(fileURLWithPath: sound))
        } catch {
            print("Audio file error.")
        }
        audioPlayer.play()
    }

    @IBAction func notePressed(_ sender: UIButton) { // Button action
        audioPlayer.stop()
    }
}

Game style:

file Sfx.swift

import AVFoundation

public let sfx = Sfx.shared
public final class Sfx: NSObject {
    
    static let shared = Sfx()
    
    var apCheer: AVAudioPlayer? = nil
    
    private override init() {
        guard let s = Bundle.main.path(forResource: "cheer", ofType: "mp3") else { return print("Sfx woe") }
        do { apCheer = try AVAudioPlayer(contentsOf: URL(fileURLWithPath: s)) } catch { return print("Sfx woe") }
    }
    
    func cheer() { apCheer?.play() }
    func plonk() { apPlonk?.play() }
    func crack() { apCrack?.play() } .. etc
}

Simply have one of these ...

    var apCheer: AVAudioPlayer? = nil

for each of your audio stings. So you may have 5, 20, 10, whatever.

For each of those, simply copy/paste the two lines of initialization code:

        guard let s = Bundle.main.path(forResource: "cheer", ofType: "mp3") else { return print("Sfx woe") }
        do { apCheer = try AVAudioPlayer(contentsOf: URL(fileURLWithPath: s)) } catch { return print("Sfx woe") }

Once you have done the above. Then, anywhere at all in any code, you can:

sfx.cheer()
sfx.crack()

it is simple and get's the job done!

import AVFoundation
var player: AVAudioPlayer!
            
    let url = Bundle.main.url(forResource: "sound_name", withExtension: "mp3")
     
    player = try! AVAudioPlayer(contentsOf: url!)
    player.play()

Tested with Swift 4 and iOS 12:

import UIKit
import AVFoundation
class ViewController: UIViewController{
    var player: AVAudioPlayer!
    override func viewDidLoad() {
        super.viewDidLoad()
    }

    func playTone(number: Int) {
        let path = Bundle.main.path(forResource: "note\(number)", ofType : "wav")!
        let url = URL(fileURLWithPath : path)
        do {
            player = try AVAudioPlayer(contentsOf: url)
            print ("note\(number)")
            player.play()
        }
        catch {
            print (error)
        }
    }

    @IBAction func notePressed(_ sender: UIButton) {
        playTone(number: sender.tag)
    }
}

First import these libraries

import AVFoundation

import AudioToolbox    

set delegate like this

   AVAudioPlayerDelegate

write this pretty code on button action or something action:

guard let url = Bundle.main.url(forResource: "ring", withExtension: "mp3") else { return }
    do {
        try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback)
        try AVAudioSession.sharedInstance().setActive(true)
        player = try AVAudioPlayer(contentsOf: url, fileTypeHint: AVFileType.mp3.rawValue)
        guard let player = player else { return }

        player.play()
    }catch let error{
        print(error.localizedDescription)
    }

100% working in my project and tested

Swift 4 (iOS 12 compatible)

var player: AVAudioPlayer?

let path = Bundle.main.path(forResource: "note\(sender.tag)", ofType: "wav")
let url = URL(fileURLWithPath: path ?? "")
    
do {
   player = try AVAudioPlayer(contentsOf: url)
   player?.play()
} catch let error {
   print(error.localizedDescription)
}
import UIKit
import AVFoundation

class ViewController: UIViewController{

    var player: AVAudioPlayer?

    override func viewDidLoad() {
        super.viewDidLoad()
    }

    @IBAction func notePressed(_ sender: UIButton) {

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

        do {
            try AVAudioSession.sharedInstance().setCategory((AVAudioSession.Category.playback), mode: .default, options: [])
            try AVAudioSession.sharedInstance().setActive(true)


            /* The following line is required for the player to work on iOS 11. Change the file type accordingly*/
            player = try AVAudioPlayer(contentsOf: url, fileTypeHint: AVFileType.wav.rawValue)

            /* iOS 10 and earlier require the following line:
             player = try AVAudioPlayer(contentsOf: url, fileTypeHint: AVFileTypeMPEGLayer3) *//

            guard let player = player else { return }

            player.play()

        } catch let error {
            print(error.localizedDescription)
        }

    }

}
import AVFoundation
var player:AVAudioPlayer!

func Play(){
    guard let path = Bundle.main.path(forResource: "KurdishSong", ofType: "mp3")else{return}
    let soundURl = URL(fileURLWithPath: path)
    player = try? AVAudioPlayer(contentsOf: soundURl)
    player.prepareToPlay()
    player.play()
    //player.pause()
    //player.stop()
}
var soundEffect = AVAudioPlayer()

func playSound(_ buttonTag : Int){

    let path = Bundle.main.path(forResource: "note\(buttonTag)", ofType : "wav")!
    let url = URL(fileURLWithPath : path)

    do{
        soundEffect = try AVAudioPlayer(contentsOf: url)
        soundEffect?.play()
        // to stop the spound .stop()
    }catch{
        print ("file could not be loaded or other error!")
    }
}

works in swift 4 latest version. ButtonTag would be a tag on a button on your interface. Notes are in a folder in a folder parallel to Main.storyboard. Every note is named as note1, note2, etc. ButtonTag is giving the number 1, 2, etc from the button clicked which is passed as param

import AVFoundation

import AudioToolbox

public final class MP3Player : NSObject {
    
    // Singleton class
    static let shared:MP3Player = MP3Player()
    
    private var player: AVAudioPlayer? = nil
    
    // Play only mp3 which are stored in the local
    public func playLocalFile(name:String) {
        guard let url = Bundle.main.url(forResource: name, withExtension: "mp3") else { return }

        do {
            try AVAudioSession.sharedInstance().setCategory(AVAudioSession.Category.playback)
            try AVAudioSession.sharedInstance().setActive(true)
            player = try AVAudioPlayer(contentsOf: url, fileTypeHint: AVFileType.mp3.rawValue)
            guard let player = player else { return }

            player.play()
        }catch let error{
            print(error.localizedDescription)
        }
    }
}

To call this function

MP3Player.shared.playLocalFile(name: "JungleBook")

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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