Jak odtworzyć dźwięk za pomocą Swift?

148

Chciałbym odtworzyć dźwięk za pomocą Swift.

Mój kod działał w Swift 1.0, ale teraz nie działa już w Swift 2 lub nowszym.

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
źródło
1
Spójrz na SwiftySound . Więcej szczegółów w tej odpowiedzi .
Adam
Jeśli chcesz tylko dźwięk z systemu, zobacz: Używanie istniejących dźwięków systemowych w aplikacji na iOS
Honey

Odpowiedzi:

291

Najkorzystniej możesz użyć AVFoundation . Zawiera wszystkie niezbędne elementy do pracy z mediami audiowizualnymi.

Aktualizacja: Kompatybilny ze Swift 2 , Swift 3 i Swift 4, zgodnie z sugestiami niektórych z was w komentarzach.


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

Szybki 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 (kompatybilny z 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)
    }
}

Pamiętaj, aby zmienić nazwę swojej melodii, a także rozszerzenie . Plik musi zostać poprawnie zaimportowany ( Project Build Phases> Copy Bundle Resources). Możesz go umieścić assets.xcassetsdla większej wygody.

W przypadku krótkich plików dźwiękowych możesz wybrać nieskompresowane formaty audio, na przykład .wavponieważ mają one najlepszą jakość i niski wpływ na procesor. W przypadku krótkich plików dźwiękowych większe zużycie miejsca na dysku nie powinno być wielkim problemem. Im dłużej pliki są, można przejść do skompresowanego formatu takiego jak .mp3itp pp. Sprawdź kompatybilnych formatów audio z CoreAudio.


Ciekawostka: istnieją zgrabne małe biblioteki, które sprawiają, że odtwarzanie dźwięków jest jeszcze łatwiejsze. :)
Na przykład: SwiftySound

Devapploper
źródło
Przepraszamy, ale ten kod już nie działa w Swift 2.0, wyświetla się błąd „Call can throw, ale nie jest oznaczony 'try' i błąd nie jest obsługiwany”
Michel Kansou
2
Wymienić bgMusic = AVAudioPlayer(contentsOfURL: bgMusicURL, fileTypeHint: nil)zdo { bgMusic = try AVAudioPlayer(contentsOfURL: bgMusicURL, fileTypeHint: nil) } catch _ { return \\ if it doesn't exist, don't play it}
saagarjha
11
Musiałem uczynić obiekt AVAudioPlayer zmienną instancji, aby to działało. Jako zmienna lokalna nie odtwarza niczego, bez błędu. Delegaci też nie byliby wzywani.
Kaleb
2
Dlaczego używasz tutaj strażnika? player = try AVAudioPlayer(contentsOf: url) guard let player = player else { return }wydaje mi się dodatkową pracą, dlaczego nie po prostu let player = try AVAudioPlayer(contentsOf: url)?
xandermonkey
2
Użycie instrukcji guard sprawia, że ​​jesteś całkiem bezpieczny przed awarią z powodu wartości zerowej.
Aashish
43

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

Najlepszą praktyką w przypadku zasobów lokalnych jest umieszczenie ich w środku assets.xcassetsi załadowanie pliku w następujący sposób:

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
źródło
Ten kod działał dla mnie na iOS 10.2.1, xCode 8.2.1. Dla mnie dwie linie „try AVAudioSession” sprawiły, że różnica między dźwiękami, które są rzeczywiście słyszalne na prawdziwym urządzeniu, czy nie. Bez nich nie ma dźwięku.
pvanallen
Bardzo mi to pomogło, dochociaż mam pewne problemy ze zrozumieniem, co dzieje się w bloku. oczywiście player!.play()jest oczywiste. Ale jaki jest cel metod setCategoryi setActive?
Shan Robertson
2
Jeśli to zrobisz, zapewni AVAudioSessionCategoryPlaybackto setCategory, że dźwięk będzie zawsze odtwarzany, nawet jeśli telefon jest w trybie blokady lub w trybie cichym. setActiveto tak, jakby powiedzieć systemowi, że Twoja aplikacja jest gotowa do odtwarzania dźwięku
Adi Nugroho,
@AdiNugroho, czy myślisz, że mógłbyś odpowiedzieć na moje pytanie: stackoverflow.com/questions/44201592/… ?
JamesG
Mam z tym dużo problemów na iOS 11. Kiedyś działało, ale teraz nagle nie działa. Jakieś pomysły?
nickdnk
15

iOS 12 - Xcode 10 beta 6 - Swift 4.2.0

Użyj tylko 1 IBAction i skieruj wszystkie przyciski na tę 1 akcję.

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
źródło
5
To zabawne, że zakładasz, że wszyscy oglądają „iOS 11 i Swift 4 - The Complete iOS App Development Bootcamp” 😂😂
karlingen
12

Jeśli kod nie generuje żadnego błędu, ale nie słychać dźwięku - utwórz odtwarzacz jako instancję:

   static var player: AVAudioPlayer!

U mnie pierwsze rozwiązanie zadziałało, gdy zrobiłem tę zmianę :)

EranKT
źródło
Pracuje dla mnie. Czy ktoś wie, dlaczego musisz ustawić to na statyczne?
kuzdu
3
Nie sądzę, że musi to być statyczne (już?), Ale wydaje się, że być może, jeśli pozwolisz mu wyjść poza zakres po utworzeniu, nawet jeśli wywołałeś play (), nie będzie odtwarzać? Właśnie utworzyłem zmienną instancji mojej klasy i działa.
biomiker
3
@kuzdu Wynika to z tego, że nie umieszczasz playertego poza zakresem. W przeciwnym razie playerzostaje zdelokalizowany i dlatego nie może odtwarzać żadnego dźwięku, ponieważ już nie istnieje.
George_E
Pracował dla mnie - bezstatic
Todd
5

Swift 4, 4,2 i 5

Odtwórz dźwięk z adresu URL i z projektu (plik lokalny)

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
źródło
3

Szybki 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
}
Panie Shin
źródło
1

Najpierw zaimportuj te biblioteki

import AVFoundation

import AudioToolbox    

ustawić delegata w ten sposób

   AVAudioPlayerDelegate

napisz ten ładny kod na akcji przycisku lub innej akcji:

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% pracujący w moim projekcie i sprawdzony

Panie Javed Multani
źródło
2
Nie ma potrzeby importowania AudioToolboxw tym miejscu.
IXany
1

Testowane z Swift 4 i 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)
    }
}
Ershin Bot
źródło
1

Swift 4 (kompatybilny z 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
źródło
Pojawia się następujący błąd: The operation couldn’t be completed. (OSStatus error 1954115647.). Szukałem wszędzie i nie mogę znaleźć rozwiązania. Może zadać pytanie na ten temat.
George_E
1

Styl gry:

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

Wszędzie w kodzie

sfx.explosion()
sfx.cheer()
Fattie
źródło
1

To jest podstawowy kod do wyszukiwania i odtwarzania pliku audio w Swift.

Dodaj plik audio do Xcode i dodaj poniższy kod.

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
źródło
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)
        }

    }

}
Hunter Akers
źródło
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!")
    }
}

działa w najnowszej wersji swift 4. ButtonTag byłby tagiem na przycisku w Twoim interfejsie. Notatki znajdują się w folderze w folderze równoległym do Main.storyboard. Każda nuta nosi nazwę note1, note2 itd. ButtonTag podaje liczbę 1, 2 itd. Z klikniętego przycisku, który jest przekazywany jako parametr

Egi Messito
źródło
0

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

}

// Aby wywołać tę funkcję

MP3Player.shared.playLocalFile (nazwa: „JungleBook”)

Nirbhay Singh
źródło
-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
źródło