Criar e reproduzir um som rapidamente


103

Então o que eu quero fazer é criar e tocar um som em swift que tocará quando eu pressionar um botão, eu sei como fazer em Objective-C, mas alguém sabe em Swift?

Seria assim para Objective-C:

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

E então, para jogar, eu faria:

AudioServicesPlaySystemSound(Explosion);

Alguém sabe como eu poderia fazer isso?


2
A raiz desta questão é como chamar funções C a partir do swift. Estou curioso sobre isso também.
67cherries

esta linha pode criar o url do som: var url :NSURL = NSURL(fileURLWithPath: NSBundle.mainBundle().pathForResource("mysoundname", ofType: "wav"))
Connor

@connor Obrigado, funciona, mas e quanto a AudioServicesCreateSystemSoundID
Jacob Banks

Não tenho certeza sobre isso. Eu só fui capaz de chamar o api objetivo-c do swift.
Connor

Respostas:


83

Aqui está um código que adicionei ao FlappySwift que funciona:

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

}

Parece que você poderia simplesmente declarar audioPlayer antes de usá-lo, mas isso não funcionou para mim no simulador. Eu tive que declarar isso no topo, assim como você fez.
Adam Loving

@Adam Loving você pode declarar audioPlayer antes de usá-lo, mas certifique-se de invocar play () na mesma função que você declarou (em oposição à boa resposta) Além disso, eu declararia coinSounde audioPlayercom em letvez de, varpois você não quer mude esses objetos em um momento posterior.
fat32

3
No Swift 2 lembre-se de executá-lo desta forma do { (player object) } catch _ { }ou você terá um bug! :)
ParisNakitaKejser

1
Mas atenção! Isso fará uma pausa na música de fundo do player. Para reproduzir um som curto, devemos usar a resposta abaixo
Nikita Pronchik

Downvote - este não é um som do sistema, está usando uma api diferente
William Entriken

119

Isso é semelhante a algumas outras respostas, mas talvez um pouco mais "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);
}

Observe que este é um exemplo trivial de reprodução do efeito do código na pergunta. Você precisará certificar-se de que import AudioToolbox, além do padrão geral para este tipo de código, carregar seus sons quando seu aplicativo for inicializado, salvando-os em SystemSoundIDvariáveis ​​de instância em algum lugar, usá-los em todo o aplicativo e, em seguida, chamar AudioServicesDisposeSystemSoundIDquando terminar com eles.


1
Você também precisa importar AudioToolbox
Brody Robertson

Você precisa ligar AudioServicesDisposeSystemSoundID(mySound)para liberar memória mais tarde? se você fizer isso imediatamente, o som basicamente não será reproduzido (é limpo instantaneamente), então eu fiz dispatch_aftere limpei 10 segundos depois.
owenfi

@owenfi O fragmento de código em minha resposta é apenas o equivalente em Swift do fragmento de código na pergunta. O padrão geral para AudioServices é carregar seus sons quando seu aplicativo é iniciado, usá-los em todo o aplicativo e descartá-los quando o aplicativo fecha, mas cada aplicativo será diferente.
Matt Gibson

@ozgur Por que você está usando uma versão desatualizada do Xcode? Precisamos saber o que "não está funcionando" significa e, provavelmente, será melhor fazer uma nova pergunta se tiver problemas específicos.
Matt Gibson

na verdade, esta é a única maneira de reproduzir um arquivo wav. AVPlayer não parece funcionar.
Haitao

18

Extensão Handy Swift:

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

Então, de qualquer lugar em seu aplicativo (lembre-se import AudioToolbox), você pode ligar

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

para tocar "sound.mp3"


Quando eu executo isso em um jogo SpriteKit, sempre há um atraso antes de o som ser reproduzido. Mesmo se eu colocar dentro DispatchQueue.global(qos: .userInitiated).async {}.
Jon Kantner

NSBundlefoi substituído por Bundle, use no Bundle.main.url(forResource: fileName, withExtension: fileExtension)lugar
diachedélico

14

Isso cria um a SystemSoundIDpartir de um arquivo chamado 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
}

Você tentou compilar o código? Estou recebendo o erro "Não é possível converter o tipo de extração '<CFURL> não gerenciado!' para digitar 'CFString' "desta linha" let soundURL = CFBundleCopyResourceURL (CFBundleGetMainBundle (), "Cha-Ching", "aiff", nil) "
bpolat

Sim, ele compila para mim. Consulte github.com/acani/Chats/blob/master/Chats/Chats/…
ma11hew28

2
Esta deve ser a resposta aceita, visto que o exemplo Obj-C fornecido é baseado no
AudioToolBox

@JochenBedersdorfer, você provavelmente está recebendo um erro devido aos objetos do Core Foundation sendo gerenciados automaticamente pela memória.
XCool

8

Com uma classe e 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)
    }
}

Uso:

testSound = Sound(name: "test", type: "caf")
testSound.play()

2
Eu amo essa resposta. Também por ser o som do sistema, não recebo a mensagem do sistema que o AVAudioPlayer joga no console para o xcode 8.
TPot

por favor me ajude, estou fazendo a mesma coisa, o som é reproduzido, mas o volume está muito baixo. não consigo ouvir
veeresh kumbar

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

É AVAudioPlayer (contentsOf: soundURL) em Swift moderno
encaixotado em

5

Este código funciona para mim. Use Try and Catch para 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()
    }
}

4
var mySound = NSSound(named:"Morse.aiff")
mySound.play()

"Morse.aiff" é um sistema de som do OSX, mas se você apenas clicar em "nomeado" no XCode, poderá visualizar (no painel QuickHelp) onde esta função está pesquisando os sons. Ele pode estar na pasta "Arquivos de suporte"


4
A questão é sobre iOS.
rmaddy

Na verdade ... Não foi possível no simulador. Nenhum documento disponível até o momento
philippe

4

De acordo com o novo Swift 2.0, devemos usar do try catch. O código ficaria assim:

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

3

isso está funcionando com o 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
Por favor, explique seu código. Respostas apenas em código são menos valiosas do que explicações.
Vincent

@Vincent +1, na verdade estou me perguntando e operadora. Isso pode ser referenciado entre som e memória.
elia

você tem que adicionar importar AudioToolbox e adicionar o código acima
Mohammad Aboelnasr

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

2

Vamos ver uma abordagem mais atualizada para esta questão:

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

1
O código funciona bem no Swift 4, mas aparentemente o som emitido não segue o volume da mídia
David Vargas

1

A solução de Matt Gibson funcionou para mim, aqui está a versão 3 do swift.

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

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

ou

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

trabalha em 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);
 }

1

Exemplo de código Swift :

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

Adicione mais detalhes sobre por que este código é útil.
Berendschot

1

Você pode tentar isso no 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()
    }

1

swift 4 e 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()    }

}


Não basta postar o código - explique o que ele faz! stackoverflow.com/help/how-to-answer
Nino Filiu

por favor consulte a pergunta deste post. Você pode encontrar sua resposta! obrigado @NinoFiliu
Gulsan Borbhuiya

0

Use esta função para fazer som em Swift (você pode usar esta função onde quiser fazer som.)

Primeiro, adicione SpriteKit e 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")

0

Este código funciona para mim:

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

0

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

0

Swift 3 é assim que eu faço.

{

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

Você não poderia simplesmente import AVFoundationselecionar o reprodutor de áudio ( var audioPlayer : AVAudioPlayer!) e reproduzir o som? ( let soundURL = Bundle.main.url(forResource: "sound", withExtension: "wav")


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

}
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.