Crear y reproducir un sonido con rapidez


103

Entonces, lo que quiero hacer es crear y reproducir un sonido en rápido que se reproducirá cuando presione un botón, sé cómo hacerlo en Objective-C, pero ¿alguien sabe cómo hacerlo en Swift?

Sería así para Objective-C:

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

Y luego para jugarlo haría:

AudioServicesPlaySystemSound(Explosion);

¿Alguien sabe cómo pude hacer esto?


2
La raíz de esta pregunta es cómo llamar a funciones C desde swift. También tengo curiosidad por esto.
67cerezas

esta línea puede crear la URL de sonido: var url :NSURL = NSURL(fileURLWithPath: NSBundle.mainBundle().pathForResource("mysoundname", ofType: "wav"))
Connor

@connor Gracias que funciona, pero ¿qué pasa con AudioServicesCreateSystemSoundID
Jacob Banks

No estoy seguro de eso. Solo he podido llamar a la API de objetivo desde Swift.
Connor

Respuestas:


83

Aquí hay un poco de código que agregué a 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 podría declarar audioPlayer justo antes de usarlo, pero eso no funcionó para mí en el simulador. Tuve que declararlo en la parte superior como lo hiciste tú.
Adam Loving

@Adam Loving, puedes declarar audioPlayer justo antes de usarlo, pero asegúrate de invocar play () en la misma función que lo declaraste (en contraposición a la buena respuesta). Además, declararía coinSoundy audioPlayercon en letlugar de varporque no quieres cambie estos objetos en un momento posterior.
fat32

3
En Swift 2, recuerde ejecutarlo de esta manera do { (player object) } catch _ { }o obtendrá un error. :)
ParisNakitaKejser

1
¡Pero atención! Pausará la música de fondo del reproductor. Para reproducir un sonido corto, debemos usar la respuesta a continuación
Nikita Pronchik

Downvote: este no es un sonido del sistema, está usando una API diferente
William Entriken

119

Esto es similar a algunas otras respuestas, pero quizás un poco más "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);
}

Tenga en cuenta que este es un ejemplo trivial que reproduce el efecto del código en la pregunta. Deberá asegurarse de hacerlo import AudioToolbox, además, el patrón general para este tipo de código sería cargar sus sonidos cuando se inicia la aplicación, guardarlos en SystemSoundIDvariables de instancia en algún lugar, usarlos en toda su aplicación y luego llamar AudioServicesDisposeSystemSoundIDcuando haya terminado con ellos.


1
También necesita importar AudioToolbox
Brody Robertson

¿Necesitas llamar AudioServicesDisposeSystemSoundID(mySound)para liberar memoria más adelante? si lo haces de inmediato, el sonido básicamente no se reproduce (se limpia instantáneamente), así que lo hice dispatch_aftery lo limpié 10 segundos después.
owenfi

@owenfi El fragmento de código en mi respuesta es solo el equivalente Swift del fragmento de código en la pregunta. El patrón general de AudioServices es cargar sus sonidos cuando se enciende la aplicación, usarlos en toda la aplicación y deshacerse de ellos cuando la aplicación se cierre, pero cada aplicación será diferente.
Matt Gibson

@ozgur ¿Por qué estás usando una versión desactualizada de Xcode? Necesitaremos saber qué significa "no funciona", y probablemente sea mejor que haga una nueva pregunta si tiene problemas específicos.
Matt Gibson

en realidad, esta es la única forma de reproducir archivos WAV. AVPlayer no parece funcionar.
Haitao

18

Extensión 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)
        }
    }
}

Luego, desde cualquier lugar de su aplicación (recuerde import AudioToolbox), puede llamar

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

para reproducir "sound.mp3"


Cuando ejecuto esto en un juego de SpriteKit, siempre hay un retraso antes de que se reproduzca el sonido. Incluso si lo pongo dentro DispatchQueue.global(qos: .userInitiated).async {}.
Jon Kantner

NSBundleha sido reemplazado por Bundle, use Bundle.main.url(forResource: fileName, withExtension: fileExtension)en su lugar
diachedelic

14

Esto crea un a SystemSoundIDpartir de un archivo llamado 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
}

¿Intentaste compilar el código? Recibo el error "No se puede convertir el tipo de extensión '¡<CFURL> no administrado!" para escribir 'CFString' "desde esta línea", deje soundURL = CFBundleCopyResourceURL (CFBundleGetMainBundle (), "Cha-Ching", "aiff", nil) "
bpolat


2
Esta debería ser la respuesta aceptada, dado que el ejemplo de Obj-C proporcionado se basa en AudioToolBox Framework
eharo2

@JochenBedersdorfer, probablemente esté recibiendo un error debido a que los objetos de Core Foundation se administran automáticamente en la memoria.
XCool

8

Con una clase y 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
Amo esta respuesta Además, debido a que es el sonido del sistema, no recibo el mensaje del sistema que AVAudioPlayer lanza en la consola para xcode 8.
TPot

por favor ayúdenme. Estoy haciendo lo mismo, se reproduce el sonido pero el volumen es demasiado bajo. no puedo oír
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()
    }
}

Es AVAudioPlayer (contentsOf: soundURL) en Swift moderno
caja el

5

Este código funciona para mí. Utilice 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" es un sonido del sistema de OSX, pero si simplemente hace clic en "nombrado" dentro de XCode, podrá ver (en el panel de Ayuda rápida) dónde esta función busca los sonidos. Puede estar en la carpeta "Archivos de apoyo".


4
La pregunta es sobre iOS.
rmaddy

De hecho ... No pude hacerlo en el simulador. No hay ningún documento disponible hasta la fecha
philippe

4

De acuerdo con el nuevo Swift 2.0 deberíamos usar do try catch. El código se vería así:

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

esto funciona con 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 su código. Las respuestas de solo código son menos valiosas que las explicaciones.
Vincent

@Vincent +1, en realidad me pregunto & operador. Esto podría estar referenciado entre el sonido y la memoria.
elia

debe agregar
Import AudioToolbox y

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

Veamos un enfoque más actualizado para esta pregunta:

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
El código funciona bien en Swift 4, pero aparentemente el sonido emitido no sigue el volumen de los medios
David Vargas

1

La solución de Matt Gibson funcionó para mí, aquí está la versión Swift 3.

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

1

Rápido 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])
    }
}
}

o

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

trabaja en 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

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

Agregue más detalles sobre por qué este código es útil.
Berendschot

1

Puedes probar esto en 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 y 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()    }

}


No se limite a publicar código, ¡explique lo que hace! stackoverflow.com/help/how-to-answer
Nino Filiu

por favor refiérase a la pregunta de esta publicación. ¡Puedes encontrar tu respuesta! gracias @NinoFiliu
Gulsan Borbhuiya

0

Use esta función para hacer sonido en Swift (puede usar esta función donde desee hacer sonido).

Primero agregue SpriteKit y 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 mí:

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, así es como lo hago.

{

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

¿No podría simplemente import AVFoundationseleccionar el reproductor de audio ( var audioPlayer : AVAudioPlayer!) y reproducir el sonido? ( 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] )
    }    

}
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.