Szybkie tworzenie i odtwarzanie dźwięku


104

Chcę więc stworzyć i odtworzyć dźwięk w języku Swift, który będzie odtwarzany po naciśnięciu przycisku. Wiem, jak to zrobić w Objective-C, ale czy ktoś wie, jak to zrobić w Swift?

Tak wyglądałoby w przypadku Objective-C:

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

A potem, żeby to zagrać, zrobiłbym:

AudioServicesPlaySystemSound(Explosion);

Czy ktoś wie, jak mogłem to zrobić?


2
Źródłem tego pytania jest wywoływanie funkcji C z poziomu swift. To też mnie ciekawi.
67cherries

ta linia może utworzyć adres URL dźwięku: var url :NSURL = NSURL(fileURLWithPath: NSBundle.mainBundle().pathForResource("mysoundname", ofType: "wav"))
Connor,

@connor Dzięki, że działa, ale co z AudioServicesCreateSystemSoundID
Jacob Banks,

Nie jestem co do tego pewien. Byłem w stanie wywołać api obiektywne-c tylko ze swift.
Connor

Odpowiedzi:


84

Oto fragment kodu, który dodałem do FlappySwift, który działa:

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

}

Wydawałoby się, że możesz po prostu zadeklarować audioPlayer tuż przed jego użyciem, ale to nie zadziałało dla mnie w symulatorze. Musiałem to zadeklarować u góry, tak jak ty.
Adam Loving

@Adam Kochanie możesz zadeklarować audioPlayer tuż przed jego użyciem, ale upewnij się, że wywołujesz funkcję play () w tej samej funkcji, w której ją zadeklarowałeś (w przeciwieństwie do dobrej odpowiedzi) Ponadto zadeklarowałbym coinSoundi audioPlayerz letzamiast, varponieważ nie chcesz zmienić te obiekty w późniejszym czasie.
fat32

3
W Swift 2 pamiętaj, aby uruchomić go w ten sposób, do { (player object) } catch _ { }albo pojawi się błąd! :)
ParisNakitaKejser

1
Ale uwaga! Wstrzyma muzykę w tle z odtwarzacza. Aby zagrać krótki dźwięk, musimy użyć odpowiedzi poniżej
Nikita Pronchik

Głos przeciw - to nie jest dźwięk systemowy, używa innego interfejsu API
William Entriken

119

Jest to podobne do innych odpowiedzi, ale być może trochę bardziej „szybkie”:

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

Zauważ, że jest to trywialny przykład odtwarzający efekt kodu w pytaniu. Musisz się upewnić import AudioToolbox, a ogólny wzorzec dla tego rodzaju kodu polegałby na ładowaniu dźwięków podczas uruchamiania aplikacji, zapisywaniu ich SystemSoundIDgdzieś w zmiennych instancji, używaniu ich w całej aplikacji, a następnie wywołaniu, AudioServicesDisposeSystemSoundIDgdy skończysz z nimi.


1
Musisz także zaimportować AudioToolbox
Brody Robertson

Czy musisz AudioServicesDisposeSystemSoundID(mySound)później zadzwonić, aby zwolnić pamięć? jeśli zrobisz to od razu, dźwięk w zasadzie nie jest odtwarzany (jest natychmiast czyszczony), więc zrobiłem dispatch_afteri wyczyściłem go 10 sekund później.
owenfi

@owenfi Fragment kodu w mojej odpowiedzi to po prostu Swiftowy odpowiednik fragmentu kodu w pytaniu. Ogólnym wzorcem dla usług AudioServices jest ładowanie dźwięków po uruchomieniu aplikacji, używanie ich w całej aplikacji i usuwanie ich po zamknięciu aplikacji, ale każda aplikacja będzie inna.
Matt Gibson,

@ozgur Dlaczego używasz nieaktualnej wersji Xcode? Będziemy musieli wiedzieć, co oznacza „nie działa” i prawdopodobnie lepiej będzie, jeśli zadasz nowe pytanie, jeśli masz konkretne problemy.
Matt Gibson,

właściwie jest to jedyny sposób na odtworzenie pliku wav. Wygląda na to, że AVPlayer nie działa.
Haitao

18

Poręczne rozszerzenie 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)
        }
    }
}

Następnie import AudioToolboxmożesz dzwonić z dowolnego miejsca w aplikacji (pamiętaj o tym )

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

aby odtworzyć „sound.mp3”


Kiedy wykonuję to w grze SpriteKit, zawsze występuje opóźnienie przed odtworzeniem dźwięku. Nawet jeśli wsadzę to do środka DispatchQueue.global(qos: .userInitiated).async {}.
Jon Kantner

NSBundlezostał zastąpiony przez Bundle, użyj Bundle.main.url(forResource: fileName, withExtension: fileExtension)zamiast tego
diachedelic

14

Tworzy to SystemSoundIDz pliku o nazwie 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
}

Czy próbowałeś skompilować kod? Otrzymuję błąd „Nie można przekonwertować typu wymuszenia„ Niezarządzany <CFURL>! ” aby wpisać „CFString” „z tego wiersza” let soundURL = CFBundleCopyResourceURL (CFBundleGetMainBundle (), „Cha-Ching”, „aiff”, nil) ”
bpolat

Tak, kompiluje się dla mnie. Zobacz github.com/acani/Chats/blob/master/Chats/Chats/…
ma11hew28

2
To powinna być akceptowana odpowiedź, biorąc pod uwagę, że podany przykład Obj-C jest oparty na programie AudioToolBox Framework
eharo2

@JochenBedersdorfer, prawdopodobnie otrzymujesz błąd z powodu automatycznego zarządzania pamięcią obiektami Core Foundation.
XCool

8

Z klasą i 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)
    }
}

Stosowanie:

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

2
Uwielbiam tę odpowiedź. Również dlatego, że jest to dźwięk systemowy, nie otrzymuję komunikatu systemowego, który AVAudioPlayer rzuca w konsoli dla xcode 8.
TPot

proszę o pomoc, robię to samo, dźwięk jest odtwarzany, ale głośność jest zbyt niska. nie słychać
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()
    }
}

To AVAudioPlayer (contentOf: soundURL) w nowoczesnym Swift
pudełku

5

Ten kod działa dla mnie. Użyj Try and Catch dla 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” to dźwięk systemowy OSX, ale jeśli po prostu klikniesz „named” w XCode, będziesz mógł zobaczyć (w panelu QuickHelp), gdzie ta funkcja wyszukuje dźwięki. Może znajdować się w folderze „Pliki pomocnicze”


4
Pytanie dotyczy iOS.
rmaddy

Rzeczywiście ... Nie mogłem tego zrobić w symulatorze. Jak dotąd brak dokumentu
philippe

4

Zgodnie z nowym Swiftem 2.0 powinniśmy używać do try catch. Kod wyglądałby tak:

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

to działa ze 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
Proszę, wyjaśnij swój kod. Odpowiedzi zawierające tylko kod są mniej wartościowe niż wyjaśnienia.
Vincent

@Vincent +1, właściwie się zastanawiam i operator. Może to odnosić się do dźwięku i pamięci.
elia

musisz dodać import AudioToolbox, a następnie dodać powyższy kod
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

Zobaczmy bardziej aktualne podejście do tego pytania:

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
Kod działa dobrze na Swift 4, ale najwyraźniej emitowany dźwięk nie podąża za głośnością mediów
David Vargas

1

Rozwiązanie Matta Gibsona zadziałało dla mnie, oto wersja Swift 3.

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

1

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

lub

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

pracuje w 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

Przykład szybkiego kodu :

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

Dodaj więcej szczegółów na temat tego, dlaczego ten kod jest pomocny.
Berendschot,

1

Możesz spróbować tego w 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 i 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()    }

}


Nie tylko wysyłaj kod - wyjaśnij, do czego służy! stackoverflow.com/help/how-to-answer
Nino Filiu

proszę odnieść się do pytania tego postu. Możesz znaleźć swoją odpowiedź! dziękuję @NinoFiliu
Gulsan Borbhuiya

0

Użyj tej funkcji, aby uzyskać dźwięk w języku Swift (możesz użyć tej funkcji, jeśli chcesz uzyskać dźwięk).

Najpierw dodaj SpriteKit i 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

Ten kod działa dla mnie:

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

Dla 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 Oto jak to zrobić.

{

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

Nie mógłbyś po prostu import AVFoundationwybrać odtwarzacza audio ( var audioPlayer : AVAudioPlayer!) i odtworzyć dźwięk? ( 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] )
    }    

}
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.