For the var testAudio declaration in my iPhone app, I am receiving an error here
"Call can throw, but errors cannot be thrown out of a property initializer"
import UIKit
import AVFoundation
class ViewController: UIViewController {
var testAudio = AVAudioPlayer(contentsOfURL: NSURL (fileURLWithPath: NSBundle.mainBundle().pathForResource("testAudio", ofType: "wav")!), fileTypeHint:nil)
This happened when I moved to the Xcode 7 beta.
How can I get this audio clip functioning in Swift 2.0?
Swift 2 has a brand new error handling system, you can read more about it here: Swift 2 Error Handling.
In your case, the AVAudioPlayer constructor can throw an error. Swift won't let you use methods that throw errors in property initializers because there is no way to handle them there. Instead, don't initialize the property until the init of the view controller.
var testAudio:AVAudioPlayer;
init() {
do {
try testAudio = AVAudioPlayer(contentsOfURL: NSURL (fileURLWithPath: NSBundle.mainBundle().pathForResource("testAudio", ofType: "wav")!), fileTypeHint:nil)
} catch {
//Handle the error
}
}
This gives you a chance to handle any errors that may come up when creating the audio player and will stop Xcode giving you warnings.
If you know an error won't be returned you can add try! beforehand:
testAudio = try! AVAudioPlayer(contentsOfURL: NSURL (fileURLWithPath: NSBundle.mainBundle().pathForResource
Works for me in Swift 2.2
But don't forget to add the fileName.mp3 to the project Build phases->Copy Bundle Resources (right click on the project root)
var player = AVAudioPlayer()
func music()
{
let url:NSURL = NSBundle.mainBundle().URLForResource("fileName", withExtension: "mp3")!
do
{
player = try AVAudioPlayer(contentsOfURL: url, fileTypeHint: nil)
}
catch let error as NSError { print(error.description) }
player.numberOfLoops = 1
player.prepareToPlay()
player.play()
}
Related
I have a WAV file with tones at around 18kHz. The audio is 16-bit PCM mono.
I am using the following function to play the file:
func playSound(name: String) {
let documents = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0]
let path = documents.appending("/").appending(name)
let url = NSURL.fileURL(withPath: path)
do {
player = try AVAudioPlayer(contentsOf: url)
guard let player = player else { return }
player.prepareToPlay()
player.play()
} catch let error {
print(error.localizedDescription)
}
}
When I play it on my iOS 10.2 device I hear a series of tones between 1000Hz to 10000Hz. I've analyzed the rendered audio by capturing it and a frequency plot shows that the original content at 18kHz is there, but there are also tones present between 1000Hz to 10000Hz. When I play the same WAV file with VLC or any other desktop audio player, I don't hear the tones (which is expected since they're located around 18kHz). I suspect that the code above isn't loading the data correctly or that the player isn't properly initialized, so I need a seasoned iOS veteran who can tell me what I'm doing wrong.
Thank you in advance.
Check the following code it might work for you
import UIKit
import AVFoundation
class ViewController: UIViewController {
var audioPlayer = AVAudioPlayer()
override func viewDidLoad() {
super.viewDidLoad()
var alertSound = NSURL(fileURLWithPath: NSBundle.mainBundle().pathForResource("button-09", ofType: "wav"))
println(alertSound)
// Removed deprecated use of AVAudioSessionDelegate protocol
AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback, error: nil)
AVAudioSession.sharedInstance().setActive(true, error: nil)
var error:NSError?
audioPlayer = AVAudioPlayer(contentsOfURL: alertSound, error: &error)
audioPlayer.prepareToPlay()
audioPlayer.play()
}
}
I'm making a Flappy Bird-type game, and I want to add a sound effect for when a coin is collected. This is what I have:
import SpriteKit
import AVFoundation
class GameScene: SKScene {
var coinSound = NSURL(fileURLWithPath:NSBundle.mainBundle().pathForResource("Super Mario Bros.- Coin Sound Effect", ofType: "mp3")!)
var audioPlayer = AVAudioPlayer()
Later in my didMoveToView:
audioPlayer = AVAudioPlayer(contentsOfURL: coinSound, error: nil)
audioPlayer.prepareToPlay()
For the second part (in my didMoveToView), the first line keeps showing an error:
Call can throw, but it is not marked with 'try' and the error is not handled
How do I fix this?
I know you already have marked an answer but if you re read this question or for future readers its easier to use SKActions to play a short 1 time sound.
AVFoundation is better used for background music.
e.g
class GameScene: SKScene {
// add as class property so sound is preloaded and always ready
let coinSound = SKAction.playSoundFileNamed("NAMEOFSOUNDFILE", waitForCompletion: false)
}
and than when you need to play the sound simply say this
run(coinSound)
Hope this helps
audioPlayer = AVAudioPlayer(contentsOfURL: coinSound, error: nil)
This is no longer the way that errors are handled in Swift. You must use the do-try-catch syntax.
do {
audioPlayer = try AVAudioPlayer(contentsOfURL: coinSound)
audioPlayer.prepareToPlay()
}
catch let error {
// handle error
}
Alternatively, if you don't care to write any error handling code, you can make your audioPlayer variable optional and write a failable try?:
audioPlayer = try? AVAudioPlayer(contentsOfURL: coinSound)
audioPlayer?.prepareToPlay()
This is more closely equivalent to the code you're attempting where you pass nil for the error parameter.
Or if crashing is the appropriate behavior when an error occurs, you could take this approach:
guard let audioPlayer = try? AVAudioPlayer(contentsOfURL: coinSound) else {
fatalError("Failed to initialize the audio player with asset: \(coinSound)")
}
audioPlayer.prepareToPlay()
self.audioPlayer = audioPlayer
Swift 3.0+
For the above guard let example from #nhgrif, this Swift 3.0+ way of doing it:
var coinSound = NSURL(fileURLWithPath:Bundle.main.path(forResource: "Super Mario Bros.- Coin Sound Effect", ofType: "mp3")!)
var audioPlayer = AVAudioPlayer()
func playCoinSound(){
guard let soundToPlay = try? AVAudioPlayer(contentsOf: coinSound as URL) else {
fatalError("Failed to initialize the audio player with asset: \(coinSound)")
}
soundToPlay.prepareToPlay()
// soundToPlay.play() // NO IDEA WHY THIS DOES NOT WORK!!!???
self.audioPlayer = soundToPlay
self.audioPlayer.play() // But this does work... please let me know why???
}
playCoinSound()
I have a sound called speeding.mp3 and I am trying to make a AVAudioPayer instance with it by doing this in the root of the class:
let speedingAudioPlayer = try! AVAudioPlayer(contentsOfURL: NSBundle.mainBundle().URLForResource("speeding", withExtension: "mp3")!)
Then when I run the app it throws an error but I don't know why this is happening. The speeding.mp3 file is in the Bundle Resources drop down in Build Phases so it should find it fine. If I try to print out the URL in the simulator and paste it into Safari it loads and plays the file like normal. I am importing AVFoundation into the class and the framework into the project.
Use this code snippet to debug your error,
if let URL = NSBundle.mainBundle().URLForResource("speeding", withExtension: "mp3") {
do {
let speedingAudioPlayer = try AVAudioPlayer(contentsOfURL: URL)
} catch let error as NSError {
print(error.localizedDescription)
}
} else {
print("No such file exist")
}
I found another question where the var is placed outside the class because otherwise it would be deallocated by the phone.
AVAudioPlayer Object Sound Not Playing - Swift
import UIKit
import AVFoundation
class CustomAudioPlayer {
var audioPlayer : AVAudioPlayer!
override func viewDidLoad() {
super.viewDidLoad()
playSound("sound_file_name")
}
func playSound(soundName: String)
{
let alertSound = NSURL(fileURLWithPath: NSBundle.mainBundle().pathForResource(soundName, ofType: "mp3")!)
do{
audioPlayer = try AVAudioPlayer(contentsOfURL:alertSound)
audioPlayer.prepareToPlay()
audioPlayer.play()
}catch {
print("Error getting the audio file")
}
}
}
Try this code for playing the sound.
Hi everyone I am trying to play a sound in swift on my xcode game on launch automatically and I have tried a bunch of different code. I was able to write and run the it in Objective - C like below in the viewdidload method, I created a method for the sound itself and called that in viewdidload.
-(void)Loadingsound {
AudioServicesPlaySystemSound(Loadingsound);
}
-(void)viewDidLoad {
[super viewDidLoad];
NSURL *LoadingSound = [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:#"Tap Sound" ofType:#"wav"]];
AudioServicesCreateSystemSoundID((__bridge CFURLRef)LoadingSound, &Loadingsound);
[self Loadingsound];
But now I am trying to replicate the same in swift but I am not able to do so. I saw this code below in another question asked on stack overflow but since now this is on Xcode 7.2.1 and Swift 2.0, is it possible that there is a new way to write this? This is the code I that I tried and the sound does not load when the game starts.
override func viewDidLoad() {
super.viewDidLoad()
if let soundURL = NSBundle.mainBundle().URLForResource("Tap Sound", withExtension: "wav") {
var mySound: SystemSoundID = 0
AudioServicesCreateSystemSoundID(soundURL, &mySound)
// Play
AudioServicesPlaySystemSound(mySound);
}
Also another way I tried of running the code was...
override func viewDidLoad() {
super.viewDidLoad()
var loadingsound = NSURL(fileURLWithPath:
NSBundle.mainBundle().pathForResource("Tap Sound", ofType: "wav"))
var audioPlayer = AVAudioPlayer()
audioPlayer = AVAudioPlayer(contentsOfURL: loadingsound, error: nil)
audioPlayer.prepareToPlay()
audioPlayer.play()
In this method when I try running it, the complies fails and shows an error which tells me to put an "!" sign after tying in "wav" and putting the bracket after that. After I put in the exclamation sign it tells me to replace the word "error" below and putin "filetypeHint" instead. Someone please help me out with this. The original was working sooo well in objective-c, can someone please help me in translating that exact code to swift. The other examples I saw as I showed were showing errors.
Thanks!
Check If your "Tap Sound" soundfile is in your project target. You need to load via URLForResource and like in my case don't set the extension type. You only need the filename. You can put it in a method like this.
func playMusic(_ filename: String) {
var audioPlayer: AVAudioPlayer?
let url = Bundle.main.url(forResource: filename, withExtension: nil)
if (url == nil) {
print("Could not find file: \(filename)")
return
}
do {
try audioPlayer = AVAudioPlayer(contentsOf: url!)
let player = audioPlayer
// From Documentation: Negative integer value to loop the sound indefinitely until you call the stop method.
player!.numberOfLoops = -1
player!.prepareToPlay()
player!.play()
} catch _ {
audioPlayer = nil;
}
}
// call the function with your soundfile
playMusic("Tap Sound")
This question already has answers here:
Playing Audio in Xcode7
(2 answers)
Closed 7 years ago.
I just started to learning Swift and,I'm trying to add a song into my code to play it when i press the button but that error shows up. how to fix this error?
var buttonAudioPlayer = AVAudioPlayer()
#IBAction func btnWarning(sender: UIButton) {
play()
}
override func viewDidLoad() {
super.viewDidLoad()
}
func play() {
let buttonAudioURL = NSURL(fileURLWithPath: NSBundle.mainBundle().pathForResource("warning", ofType: "mp3")!)
let one = 1
if one == 1 {
buttonAudioPlayer = AVAudioPlayer(contentsOfURL: buttonAudioURL) //getting the error in this line
buttonAudioPlayer.prepareToPlay()
buttonAudioPlayer.play()
}
}
The compiler correctly tells you that the initializer can throw an error as the method declaration correctly states (e.g. when the NSURL does not exist):
init(contentsOfURL url: NSURL) throws
Therefore you as the developer have to handle an eventually occuring error:
do {
let buttonAudioPlayer = try AVAudioPlayer(contentsOfURL: buttonAudioURL)
} catch let error {
print("error occured \(error)")
}
Alternatively you can tell the compiler that the call will actually always succeed via
let buttonAudioPlayer = try! AVAudioPlayer(contentsOfURL: buttonAudioURL)
But that will cause your app to crash if the creation actually does not succeed - be careful. You only should use the second approach if you are trying to load app resources that have to be there.
There is a possibility that AVAudioPlayer(contentsOfURL: buttonAudioURL) may throw an exception. So you need to add exception handler code.
do {
try buttonAudioPlayer = AVAudioPlayer(contentsOfURL: buttonAudioURL)
} catch {
//handle exception here
}