Comment jouer un son avec Swift?

149

Je voudrais jouer un son avec Swift.

Mon code fonctionnait dans Swift 1.0 mais maintenant il ne fonctionne plus dans Swift 2 ou plus récent.

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
  }
}
Michel Kansou
la source
1
Jetez un œil à SwiftySound . Plus de détails dans cette réponse .
Adam le
Si vous voulez juste un son du système, consultez: Utilisation des sons du système existants dans l'application iOS
Honey

Réponses:

293

De préférence, vous pouvez utiliser AVFoundation . Il fournit tous les éléments essentiels pour travailler avec les médias audiovisuels.

Mise à jour: Compatible avec Swift 2 , Swift 3 et Swift 4 comme suggéré par certains d'entre vous dans les commentaires.


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 (compatible iOS 13)

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)
    }
}

Assurez-vous de changer le nom de votre morceau ainsi que l' extension . Le fichier doit être correctement importé ( Project Build Phases> Copy Bundle Resources). Vous voudrez peut-être le placer assets.xcassetspour plus de commodité.

Pour les fichiers son courts, vous voudrez peut-être opter pour des formats audio non compressés, par exemple, .wavcar ils ont la meilleure qualité et un faible impact sur le processeur. La consommation d'espace disque plus élevée ne devrait pas être un problème pour les fichiers son courts. Plus les fichiers sont longs, vous voudrez peut-être opter pour un format compressé tel que .mp3etc. pp. Vérifiez les formats audio compatibles de CoreAudio.


Fait amusant: il existe de jolies petites bibliothèques qui facilitent encore plus la lecture des sons. :)
Par exemple: SwiftySound

Devapploper
la source
Désolé mais ce code ne fonctionne plus dans swift 2.0 il affiche une erreur "L'appel peut lancer, mais il n'est pas marqué avec 'try' et l'erreur n'est pas gérée"
Michel Kansou
2
Remplacer bgMusic = AVAudioPlayer(contentsOfURL: bgMusicURL, fileTypeHint: nil)pardo { bgMusic = try AVAudioPlayer(contentsOfURL: bgMusicURL, fileTypeHint: nil) } catch _ { return \\ if it doesn't exist, don't play it}
saagarjha
11
J'ai dû faire de l'objet AVAudioPlayer une variable d'instance pour que cela fonctionne. En tant que variable locale, elle ne jouerait rien, aucune erreur. Les délégués ne seraient pas appelés non plus.
Kaleb
2
Pourquoi utilisez-vous un garde ici? player = try AVAudioPlayer(contentsOf: url) guard let player = player else { return }me semble être un travail supplémentaire, pourquoi pas simplement let player = try AVAudioPlayer(contentsOf: url)?
xandermonkey
2
L'utilisation d'une instruction de garde vous évite de tomber en panne en raison d'une valeur nulle.
Aashish
43

Pour 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)")
    }
}

La meilleure pratique pour les actifs locaux est de le mettre à l'intérieur assets.xcassetset de charger le fichier comme ceci:

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)")
    }
}
Adi Nugroho
la source
Ce code a fonctionné pour moi sur iOS 10.2.1, xCode 8.2.1. Pour moi, les deux lignes «essayez AVAudioSession» ont fait la différence entre les sons réellement entendus sur un appareil réel ou non. Sans eux, pas de son.
pvanallen le
Cela m'a beaucoup aidé, j'ai du mal à comprendre ce qui se passe dans le dobloc. player!.play()est évidemment explicite. Mais quel est le but des méthodes setCategoryet setActive?
Shan Robertson
2
Si vous fournissez AVAudioSessionCategoryPlaybackà setCategory, il veillera à ce que l'audio est toujours joué , même si le téléphone est dans l' écran de verrouillage ou en mode silencieux. setActivec'est comme dire au système que votre application est prête à lire de l'audio
Adi Nugroho
@AdiNugroho pensez-vous que vous pourriez aider avec ma question: stackoverflow.com/questions/44201592/… ?
JamesG
J'ai beaucoup de problèmes avec cela sur iOS 11. Cela fonctionnait mais maintenant ça ne marche plus. Des idées?
nickdnk
15

iOS 12 - Xcode 10 bêta 6 - Swift 4.2

Utilisez juste 1 IBAction et pointez tous les boutons sur cette 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!")
    }
}
Tony Ward
la source
5
C'est drôle que vous supposiez que tout le monde regarde "iOS 11 et Swift 4 - Le bootcamp complet de développement d'applications iOS" 😂😂
karlingen
12

Si le code ne génère aucune erreur, mais que vous n'entendez pas de son, créez le lecteur comme une instance:

   static var player: AVAudioPlayer!

Pour moi, la première solution a fonctionné lorsque j'ai fait ce changement :)

EranKT
la source
Travaille pour moi. Est-ce que quelqu'un sait pourquoi vous devez définir cela sur statique?
kuzdu
3
Je ne pense pas qu'il doive être statique (plus?), Mais il semble peut-être que si vous le laissez sortir de la portée après sa création, même si vous avez appelé play (), il ne jouera pas? Je viens d'en faire une variable d'instance de ma classe et cela fonctionne.
biomiker
3
@kuzdu Cela est dû au fait que vous ne placez pas le playerdans la portée extérieure. Sinon, il playerest délocalisé et ne peut donc pas jouer de son car il n'existe plus.
George_E
A travaillé pour moi - sansstatic
Todd
5

Swift 4, 4.2 et 5

Lire l'audio depuis l'URL et depuis votre projet (fichier local)

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()
    }

}
Akbar Khan
la source
3

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
}
Monsieur Shin
la source
1

Importez d'abord ces bibliothèques

import AVFoundation

import AudioToolbox    

définir le délégué comme ceci

   AVAudioPlayerDelegate

écrivez ce joli code sur l'action de bouton ou quelque chose d'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% travaillant dans mon projet et testé

Monsieur Javed Multani
la source
2
Il n'est pas nécessaire d'importer AudioToolboxà cet endroit.
ixany
1

Testé avec Swift 4 et 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)
    }
}
Bot Ershin
la source
1

Swift 4 (compatible iOS 12)

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)
}
imdpk
la source
Je reçois l'erreur suivante: The operation couldn’t be completed. (OSStatus error 1954115647.). J'ai cherché partout et je ne trouve pas de solution. Pourrait poster une question à ce sujet.
George_E
1

Style de jeu:

fichier 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 {
            apComment = try AVAudioPlayer(contentsOf: URL(fileURLWithPath: s))
        } catch {
            return  print("Sfx woe")
        }
    }
    
    func cheer() { apCheer?.play() }
    func plonk() { apPlonk?.play() }
    func crack() { apCrack?.play() } .. etc
}

Partout dans le code

sfx.explosion()
sfx.cheer()
Fattie
la source
1

Il s'agit d'un code de base pour rechercher et lire un fichier audio dans Swift.

Ajoutez votre fichier audio à votre Xcode et ajoutez le code ci-dessous.

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()
    }
}
M VIJAY
la source
0
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)
        }

    }

}
Chasseur Akers
la source
0
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!")
    }
}

fonctionne dans la dernière version de swift 4. ButtonTag serait une balise sur un bouton de votre interface. Les notes sont dans un dossier dans un dossier parallèle à Main.storyboard. Chaque note est nommée note1, note2, etc. ButtonTag donne le numéro 1, 2, etc. à partir du bouton cliqué qui est passé en paramètre

Egi Messito
la source
0

importer AVFoundation

importer 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)
    }
}

}

// Pour appeler cette fonction

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

Nirbhay Singh
la source
-1
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()
}
Mobin Valadi
la source