105

So what I want to do is create and play a sound in swift that will play when I press a button, I know how to do it in Objective-C, but does anyone know how to in Swift?

It would be like this for Objective-C:

NSURL *soundURL = [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"mysoundname" ofType:@"wav"]];
AudioServicesCreateSystemSoundID((__bridge CFURLRef)soundURL, &mySound);

And then to play it I would do:

AudioServicesPlaySystemSound(Explosion);

Does anyone know how I could do this?

Scott
  • 21,211
  • 8
  • 65
  • 72
Jacob Banks
  • 1,217
  • 2
  • 10
  • 9

24 Answers24

126

This is similar to some other answers, but perhaps a little more "Swifty":

// Load "mysoundname.wav"
if let soundURL = Bundle.main.url(forResource: "mysoundname", withExtension: "wav") {
    var mySound: SystemSoundID = 0
    AudioServicesCreateSystemSoundID(soundURL as CFURL, &mySound)
    // Play
    AudioServicesPlaySystemSound(mySound);
}

Note that this is a trivial example reproducing the effect of the code in the question. You'll need to make sure to import AudioToolbox, plus the general pattern for this kind of code would be to load your sounds when your app starts up, saving them in SystemSoundID instance variables somewhere, use them throughout your app, then call AudioServicesDisposeSystemSoundID when you're finished with them.

Gianmarco
  • 23
  • 1
  • 7
Matt Gibson
  • 37,886
  • 9
  • 99
  • 128
  • 1
    You also need to import AudioToolbox – Brody Robertson Sep 20 '15 at 05:25
  • 1
    Do you need to call `AudioServicesDisposeSystemSoundID(mySound)` to free up the memory later on? if you do it right away the sound basically doesn't play (gets cleaned up instantly) so I did `dispatch_after` and cleaned it up 10 seconds later. – owenfi Sep 21 '15 at 07:08
  • @owenfi The fragment of code in my answer is just the Swift equivalent of the fragment of code in the question. The general pattern for AudioServices is to load up your sounds when your app fires up, use them throughout the app, and dispose of them when the app closes, but each app will be different. – Matt Gibson Sep 21 '15 at 07:26
  • @ozgur Why are you using an out-of-date version of Xcode? We'll need to know what "not working" means, and you'll probably be better off asking a new question if you have specific issues. – Matt Gibson Feb 17 '16 at 12:02
  • actually this is the only way to play wav file. AVPlayer doesn't seem to work. – Haitao Aug 23 '17 at 22:57
83

Here's a bit of code I've got added to FlappySwift that works:

import SpriteKit
import AVFoundation

class GameScene: SKScene {

    // Grab the path, make sure to add it to your project!
    var coinSound = NSURL(fileURLWithPath: Bundle.main.path(forResource: "coin", ofType: "wav")!)
    var audioPlayer = AVAudioPlayer()

    // Initial setup
    override func didMoveToView(view: SKView) {
        audioPlayer = AVAudioPlayer(contentsOfURL: coinSound, error: nil)
        audioPlayer.prepareToPlay()
    }

    // Trigger the sound effect when the player grabs the coin
    func didBeginContact(contact: SKPhysicsContact!) {
        audioPlayer.play()
    }

}
Gianmarco
  • 23
  • 1
  • 7
Bauerpauer
  • 930
  • 6
  • 3
  • It would seem you could just declare audioPlayer right before using it, but that didn't work for me in the simulator. I had to declare it at the top just like you did. – Adam Loving Oct 30 '14 at 19:02
  • @Adam Loving you can declare audioPlayer right before using it, but make sure you invoke play() in the same function you declared it (as opposed to the good answer) Further, I would declare `coinSound` and `audioPlayer` with `let` instead of `var` since you do not want to change these objects at a later point in time. – fat32 Jan 28 '15 at 18:46
  • 3
    In Swift 2 remember to run it this way `do { (player object) } catch _ { }` or your will get a bug! :) – ParisNakitaKejser Jun 26 '15 at 20:02
  • 1
    But attention! It will pause background music from player. To play short sound we must use answer below – Nikita Semenov Jul 15 '15 at 09:41
  • Downvote -- this is not a system sound, it is using a different api – William Entriken Feb 20 '16 at 20:51
18

Handy Swift extension:

import AudioToolbox

extension SystemSoundID {
    static func playFileNamed(fileName: String, withExtenstion fileExtension: String) {
        var sound: SystemSoundID = 0
        if let soundURL = NSBundle.mainBundle().URLForResource(fileName, withExtension: fileExtension) {
            AudioServicesCreateSystemSoundID(soundURL, &sound)
            AudioServicesPlaySystemSound(sound)
        }
    }
}

Then, from anywhere in your app (remember to import AudioToolbox), you can call

SystemSoundID.playFileNamed("sound", withExtenstion: "mp3")

to play "sound.mp3"

John R Perry
  • 3,916
  • 2
  • 38
  • 62
Aleix Pinardell
  • 271
  • 2
  • 8
  • When I execute this in a SpriteKit game, there’s always lag before the sound is played. Even if I put it inside `DispatchQueue.global(qos: .userInitiated).async {}`. – Jon Kantner Aug 29 '18 at 15:52
  • 1
    `NSBundle` has been replaced by `Bundle`, use `Bundle.main.url(forResource: fileName, withExtension: fileExtension)` instead – diachedelic May 27 '20 at 02:47
14

This creates a SystemSoundID from a file called Cha-Ching.aiff.

import AudioToolbox

let chaChingSound: SystemSoundID = createChaChingSound()

class CashRegisterViewController: UIViewController {
    override func viewWillAppear(animated: Bool) {
        super.viewWillAppear(animated)
        AudioServicesPlaySystemSound(chaChingSound)
    }
}

func createChaChingSound() -> SystemSoundID {
    var soundID: SystemSoundID = 0
    let soundURL = CFBundleCopyResourceURL(CFBundleGetMainBundle(), "Cha-Ching", "aiff", nil)
    AudioServicesCreateSystemSoundID(soundURL, &soundID)
    CFRelease(soundURL)
    return soundID
}
ma11hew28
  • 121,420
  • 116
  • 450
  • 651
  • Did you try to compile the code? I am getting error "Cannot convert the extression's type 'Unmanaged !' to type 'CFString'" from this line "let soundURL = CFBundleCopyResourceURL(CFBundleGetMainBundle(), "Cha-Ching", "aiff", nil)" – bpolat Jul 13 '14 at 19:09
  • Yes, it compiles for me. See https://github.com/acani/Chats/blob/master/Chats/Chats/ChatViewController.swift#L296 – ma11hew28 Jul 19 '14 at 13:46
  • 2
    This should be the accepted answer, given that the Obj-C example provided is based in the AudioToolBox Framework – eharo2 Sep 02 '14 at 15:04
  • @JochenBedersdorfer, you're probably getting an error due to Core Foundation objects being automatically memory managed. – XCool May 12 '15 at 04:48
8

With a class & AudioToolbox:

import AudioToolbox

class Sound {

    var soundEffect: SystemSoundID = 0
    init(name: String, type: String) {
        let path  = NSBundle.mainBundle().pathForResource(name, ofType: type)!
        let pathURL = NSURL(fileURLWithPath: path)
        AudioServicesCreateSystemSoundID(pathURL as CFURLRef, &soundEffect)
    }

    func play() {
        AudioServicesPlaySystemSound(soundEffect)
    }
}

Usage:

testSound = Sound(name: "test", type: "caf")
testSound.play()
karimhossenbux
  • 162
  • 2
  • 13
  • 2
    I love this answer. Also because it is the system sound, I don't get the system message the AVAudioPlayer throws in the console for xcode 8. – TPot Jan 15 '17 at 10:49
  • please help i am doing the same thing, sound plays but the volume is too low. cannot hear – veeresh kumbar May 22 '19 at 12:30
6
import AVFoundation

var audioPlayer = AVAudioPlayer()

class GameScene: SKScene {

    override func didMoveToView(view: SKView) {

        let soundURL = NSBundle.mainBundle().URLForResource("04", withExtension: "mp3")
        audioPlayer = AVAudioPlayer(contentsOfURL: soundURL, error: nil)
        audioPlayer.play()
    }
}
Michael N
  • 436
  • 5
  • 6
5

This code works for me. Use Try and Catch for AVAudioPlayer

import UIKit
import AVFoundation
class ViewController: UIViewController {

    //Make sure that sound file is present in your Project.
    var CatSound = NSURL(fileURLWithPath: NSBundle.mainBundle().pathForResource("Meow-sounds.mp3", ofType: "mp3")!)
    var audioPlayer = AVAudioPlayer()

    override func viewDidLoad() {
        super.viewDidLoad()

        do {

            audioPlayer = try AVAudioPlayer(contentsOfURL: CatSound)
            audioPlayer.prepareToPlay()

        } catch {

            print("Problem in getting File")

        }      
        // Do any additional setup after loading the view, typically from a nib.
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    @IBAction func button1Action(sender: AnyObject) {

        audioPlayer.play()
    }
}
Tunaki
  • 132,869
  • 46
  • 340
  • 423
Sachin Dobariya
  • 744
  • 7
  • 16
4
var mySound = NSSound(named:"Morse.aiff")
mySound.play()

"Morse.aiff" is a system sound of OSX, but if you just click on "named" within XCode, you'll be able to view (in the QuickHelp pane) where this function is searching the sounds. It can be in your "Supporting files" folder

philippe
  • 1,877
  • 2
  • 20
  • 25
4

According to new Swift 2.0 we should use do try catch. The code would look like this:

var badumSound = NSURL(fileURLWithPath: NSBundle.mainBundle().pathForResource("BadumTss", ofType: "mp3"))
var audioPlayer = AVAudioPlayer()
 do {
     player = try AVAudioPlayer(contentsOfURL: badumSound)
 } catch {
     print("No sound found by URL:\(badumSound)")
 }
 player.prepareToPlay()
Roman Safin
  • 704
  • 7
  • 16
3

this is working with Swift 4 :

if let soundURL = Bundle.main.url(forResource: "note3", withExtension: "wav") {
                var mySound: SystemSoundID = 0
                AudioServicesCreateSystemSoundID(soundURL as CFURL, &mySound)
                // Play
                AudioServicesPlaySystemSound(mySound);
            }
2
//Swift 4
import UIKit
import AVFoundation

class ViewController: UIViewController {

    var player : AVAudioPlayer?

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

    @IBAction func notePressed(_ sender: UIButton) {
        let path = Bundle.main.path(forResource: "note1", ofType: "wav")!
        let url = URL(fileURLWithPath: path)
        do {
            player = try AVAudioPlayer(contentsOf: url)
            player?.play()
        } catch {
            // error message
        }
    }
}
mag_zbc
  • 6,801
  • 14
  • 40
  • 62
Soma Sharma
  • 73
  • 15
2

Let us see a more updated approach to this question:

Import AudioToolbox

func noteSelector(noteNumber: String) {

    if let soundURL = Bundle.main.url(forResource: noteNumber, withExtension: "wav") {
        var mySound: SystemSoundID = 0
        AudioServicesCreateSystemSoundID(soundURL as CFURL, &mySound)
        AudioServicesPlaySystemSound(mySound)
}
Adam Eberbach
  • 12,309
  • 6
  • 62
  • 114
  • 1
    The code works fine on Swift 4, but apparently the emitted sound does not follow the media volume – David Apr 10 '19 at 12:30
2

You can try this in Swift 5.2

func playSound() {
        let soundURL = Bundle.main.url(forResource: selectedSoundFileName, withExtension: "wav")
        do {
            audioPlayer = try AVAudioPlayer(contentsOf: soundURL!)
        }
        catch {
            print(error)
        }
        audioPlayer.play()
    }
Xab Ion
  • 1,105
  • 1
  • 11
  • 20
2
import UIKit
import AudioToolbox

class ViewController: UIViewController {

    let toneSound : Array =  ["note1","note2","note3","note4","note5","note6"]

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.

    }

    func playSound(theTone : String) {
        if let soundURL = Bundle.main.url(forResource: theTone, withExtension: "wav") {
            var mySound: SystemSoundID = 0
            do {
                AudioServicesCreateSystemSoundID(soundURL as CFURL, &mySound)
                // Play
                AudioServicesPlaySystemSound(mySound);
            }
            catch {
               print(error)
            }
        }
    }

    @IBAction func anypressed(_ sender: UIButton) {
        playSound(theTone: toneSound[sender.tag-1] )
    }    

}
General Failure
  • 2,421
  • 4
  • 23
  • 49
IslamNazir
  • 21
  • 2
1

For Swift 3:

extension SystemSoundID {
    static func playFileNamed(_ fileName: String, withExtenstion fileExtension: String) {
        var sound: SystemSoundID = 0
        if let soundURL = Bundle.main.url(forResource: fileName, withExtension: fileExtension) {
            AudioServicesCreateSystemSoundID(soundURL as CFURL, &sound)
            AudioServicesPlaySystemSound(sound)
        }
    }
}
He Yifei 何一非
  • 2,592
  • 4
  • 38
  • 69
1

Matt Gibson's solution worked for me, here is the swift 3 version.

if let soundURL = Bundle.main.url(forResource: "ringSound", withExtension: "aiff") {
  var mySound: SystemSoundID = 0
  AudioServicesCreateSystemSoundID(soundURL as CFURL, &mySound)
  AudioServicesPlaySystemSound(mySound);
}
Pavle Mijatovic
  • 773
  • 10
  • 6
1

Swift 4

import UIKit
import AudioToolbox

class ViewController: UIViewController{

var sounds : [SystemSoundID] = [1, 2, 3, 4, 5, 6, 7]

override func viewDidLoad() {
    super.viewDidLoad()

    for index in 0...sounds.count-1 {
        let fileName : String = "note\(sounds[index])"

        if let soundURL = Bundle.main.url(forResource: fileName, withExtension: "wav") {
            AudioServicesCreateSystemSoundID(soundURL as CFURL, &sounds[index])
        }
    }
}



@IBAction func notePressed(_ sender: UIButton) {
    switch sender.tag {
    case 1:
        AudioServicesPlaySystemSound(sounds[0])
    case 2:
        AudioServicesPlaySystemSound(sounds[1])
    case 3:
        AudioServicesPlaySystemSound(sounds[2])
    case 4:
        AudioServicesPlaySystemSound(sounds[3])
    case 5:
        AudioServicesPlaySystemSound(sounds[4])
    case 6:
        AudioServicesPlaySystemSound(sounds[5])
    default:
        AudioServicesPlaySystemSound(sounds[6])
    }
}
}

or

import UIKit
import AVFoundation

class ViewController: UIViewController, AVAudioPlayerDelegate{

var audioPlayer : AVAudioPlayer!

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

@IBAction func notePressed(_ sender: UIButton) {

    let soundURL = Bundle.main.url(forResource: "note\(sender.tag)", withExtension: "wav")

    do {
        audioPlayer = try AVAudioPlayer(contentsOf: soundURL!)
    }
    catch {
        print(error)
    }

    audioPlayer.play()

}
}
1

works in Xcode 9.2

if let soundURL = Bundle.main.url(forResource: "note1", withExtension: "wav") {
   var mySound: SystemSoundID = 0
   AudioServicesCreateSystemSoundID(soundURL as CFURL, &mySound)
   // Play
    AudioServicesPlaySystemSound(mySound);
 }
MAhipal Singh
  • 4,745
  • 1
  • 42
  • 57
Ray Sawyer
  • 11
  • 1
1

Swift code example:

import UIKit
import AudioToolbox

class ViewController: UIViewController {  

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

@IBAction func notePressed(_ sender: UIButton) {

    // Load "mysoundname.wav"

    if let soundURL = Bundle.main.url(forResource: "note1", withExtension: "wav") {
        var mySound: SystemSoundID = 0
        AudioServicesCreateSystemSoundID(soundURL as CFURL, &mySound)
    // Play

        AudioServicesPlaySystemSound(mySound);
    }
}
Berendschot
  • 3,026
  • 1
  • 21
  • 43
Pawel
  • 11
  • 1
1

swift 4 & iOS 12

var audioPlayer: AVAudioPlayer?

override func viewDidLoad() {
    super.viewDidLoad()



}

@IBAction func notePressed(_ sender: UIButton) {

    // noise while pressing button

    _ = Bundle.main.path(forResource: "note1", ofType: "wav")

    if Bundle.main.path(forResource: "note1", ofType: "wav") != nil {
        print("Continue processing")
    } else {
        print("Error: No file with specified name exists")
    }

    do {
        if let fileURL = Bundle.main.path(forResource: "note1", ofType: "wav") {
            audioPlayer = try AVAudioPlayer(contentsOf: URL(fileURLWithPath: fileURL))
        } else {
            print("No file with specified name exists")
        }
    } catch let error {
        print("Can't play the audio file failed with an error \(error.localizedDescription)")
    }


    audioPlayer?.play()    }

}

Gulsan Borbhuiya
  • 188
  • 2
  • 11
0

Use This Function to make sound in Swift (You can use this function where you want to make sound.)

First Add SpriteKit and AVFoundation Framework.

import SpriteKit
import AVFoundation
 func playEffectSound(filename: String){
   runAction(SKAction.playSoundFileNamed("\(filename)", waitForCompletion: false))
 }// use this function to play sound

playEffectSound("Sound File Name With Extension")
// Example :- playEffectSound("BS_SpiderWeb_CollectEgg_SFX.mp3")
Raksha Saini
  • 604
  • 12
  • 28
0

This code works for me:

class ViewController: UIViewController {

    var audioFilePathURL : NSURL!
    var soundSystemServicesId : SystemSoundID = 0

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        audioFilePathURL = NSBundle.mainBundle().URLForResource("MetalBell", withExtension: "wav")

        AudioServicesCreateSystemSoundID( audioFilePathURL, &soundSystemServicesId)


    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.


    }


    @IBAction func PlayAlertSound(sender: UIButton) {

         AudioServicesPlayAlertSound(soundSystemServicesId)
    }
}
ArtKorchagin
  • 4,801
  • 13
  • 42
  • 58
Jeeva
  • 162
  • 1
  • 9
0

Swift 3 here's how i do it.

{

import UIKit
import AVFoundation

        let url = Bundle.main.url(forResource: "yoursoundname", withExtension: "wav")!
        do {

            player = try AVAudioPlayer(contentsOf: url); guard let player = player else { return }

            player.prepareToPlay()
            player.play()
        } catch let error as Error {
            print(error)

        }
    }
0

Couldn't you just import AVFoundation, select the audio player (var audioPlayer : AVAudioPlayer!), and play the sound? (let soundURL = Bundle.main.url(forResource: "sound", withExtension: "wav")