I have made a class which handles audio that is played in my app:
import AVFoundation
class GSAudio{
var soundFileNameURL: NSURL = NSURL()
var soundFileName = ""
var soundPlay = AVAudioPlayer()
func playSound (soundFile: String){
soundFileName = soundFile
soundFileNameURL = NSURL(fileURLWithPath: NSBundle.mainBundle().pathForResource(soundFileName, ofType: "aif", inDirectory:"Sounds")!)
do{
try soundPlay = AVAudioPlayer(contentsOfURL: soundFileNameURL)
} catch {
print("Could not play sound file!")
}
soundPlay.prepareToPlay()
soundPlay.play()
}
}
But the problem is when I call this code by using something like GSAudio().playSound("Start") from a different class, the sound does not play. Does anyone know why this is? Any help is appreciated.
Many thanks.
I have method AVAudioPlayer and its working fine when the button click action then perform this below method play well, but You want to call class and method (ex 'GSAudio().playSound("Start")') from different class, you create the delegate method to call, its work well.
#IBAction func btnPlayAction(sender: AnyObject) {
let fileURL: NSURL = NSURL(string: previewUrl)!
let soundData = NSData(contentsOfURL: fileURL)
do {
playerVal = try AVAudioPlayer(data: soundData!)
}
catch {
print("Something bad happened. Try catching specific errors to narrow things down",error)
}
playerVal.delegate = self
playerVal.prepareToPlay()
playerVal.play()
}
hope its helpful
Check Your Sound File (URL) Path..(print That) and Checkout file:// Is There Or Not That's Main Problem In Your Sound ULR Ok Add it File://
//Or Use this One
NSURL *SoundURL = [NSURL fileURLWithPath:YourFilePath];
Try This One And Let me Know is i'm Correct or not
I have a helper on GitHub that does what you want. It's properly better to make this class a Singleton so you can control your music better and don't create multiple instances of your helper.
https://github.com/crashoverride777/Swift-Music-Helper
Related
The sound file is playing when i add breakpoints inside the below functions. But the sound file is not playing if i run the application without breakpoint.
I am calling this function in button click as Sound().playSounds()
import AVFoundation
class Sound {
private var audioplayer:AVAudioPlayer!
func playSounds()
{
if let path = Bundle.main.path(forResource: "Audio/ring.mp3", ofType: nil)
{
let url = URL(fileURLWithPath: path)
do {
self.audioplayer = try AVAudioPlayer(contentsOf: url)
self.audioplayer.numberOfLoops = 3
self.audioplayer.prepareToPlay()
self.audioplayer.play()
}
catch {
print("Couldn't load file")
}
}
}
}
Your Sound object gets deallocated before it has a chance to play a sound.
Store it where you are calling it from:
var sound = Sound()
// for example to play sound call
func playPressed(){
sound.playSounds()
}
Chane your player into a global variable like this. Otherwise it'll be a deadlock.
var audioplayer:AVAudioPlayer!
Also you may want to change your resource path extracting logic to below,
if let path = Bundle.main.path(forResource: "ring.mp3", ofType: "mp3")
Or you can directly use Bundle.main.url(forResource: withExtention) method.
I am using xcode 9 and swift 4 for my app. In my app i have music playing in the viewDidLoad. When i exit the view controller to go to another View, it continues to play like it should. How ever, when i return to that view controller the song starts to play again. This song is overlapping the song that first loaded. Do you guys have any ideas on how to stop this from happening?
do
{
let audioPath = Bundle.main.path(forResource: "APP4", ofType: "mp3")
try player = AVAudioPlayer(contentsOf: NSURL(fileURLWithPath: audioPath!) as URL)
}
catch
{
//catch error
}
let session = AVAudioSession.sharedInstance()
do
{
try session.setCategory(AVAudioSessionCategoryPlayback)
}
catch
{
}
player.numberOfLoops = -1
player.play()
It starts playing again, because your viewDidLoad is called again, which asks it to play it again. A simplest fix would be to keep a static bool variable to keep track if you have already made this call.
static var isMusicPlaying: Bool = false
In your viewDidLoad, you can put code before the code that calls the play.
guard !isMusicPlaying else {
return
}
isMusicPlaying = true
I'm new in Swift. I am trying to Run this code but got an error:
Thread 1: EXC_BAD_ACCESS (code=1, address=0x48) a.
Error appears here:
self.player.play()
Can anyone help in this issue?
import UIKit
import AVFoundation
class ViewController: UIViewController {
var player = AVAudioPlayer()
override func viewDidLoad() {
super.viewDidLoad()
do {
if let audioPath = Bundle.main.path(forResource: "music", ofType: "mp3") {
try player = AVAudioPlayer(contentsOf: URL(fileURLWithPath: audioPath))
}
} catch {
print("ERROR")
}
self.player.play()
}
What you doing with your code is:
Creating an instance of AVAudioPlayer without any data
Trying to create a new instance with some data from music.mp3 file
Playing it
If the audioPath is not correct, then the player is not correctly created: application will use the one without valid data, leading to a crash during playback.
Your code can be written making the player optional, which helps preventing the crash:
import UIKit
import AVFoundation
class ViewController: UIViewController {
var player: AVAudioPlayer?
override func viewDidLoad() {
super.viewDidLoad()
player = initializePlayer()
player?.play()
}
private func initializePlayer() -> AVAudioPlayer? {
guard let path = Bundle.main.path(forResource: "music", ofType: "mp3") else {
return nil
}
return try? AVAudioPlayer(contentsOf: URL(fileURLWithPath: path))
}
}
Some changes performed to the code:
player is now optional: there is no need to initialize it twice. Plus if the initialization goes well you can use it without problems, otherwise your app won't crash.
The play method is now in an optional chain
I've moved the initialization of the player in a separate private methods, to maintain the code readable. Feel free to change it, it is just a suggestion.
I've got it. The issue is that the file isn't being coping to my app bundle. To fix it:
Click your project
Click your target
Select Build Phases
Expand Copy Bundle Resources
Click '+' and select your file.
Thanks Denis Hennessy
I'm current developing a small game where balloons float up from the bottom of the screen and the player has to pop them before they reach the top.
Each balloon object contains a method to safely set up it's AVAudioPlayer's:
func setUpAudioPlayerWithFile(file:NSString, type:NSString) -> AVAudioPlayer? {
let path = NSBundle.mainBundle().pathForResource(file as String, ofType: type as String)
let url = NSURL.fileURLWithPath(path!)
var audioPlayer:AVAudioPlayer?
do {
try audioPlayer = AVAudioPlayer(contentsOfURL: url)
}catch {
print("BALLOON ERROR - AudioPlayer not avaliable.")
}
return audioPlayer
}
Then in each balloons init() method I run the following code:
if let popSound = self.setUpAudioPlayerWithFile("PopSound", type: "wav") {
self.popSound = popSound
}
Which works absolutely fine until a couple of minutes into the game. At this point I start receiving "BALLOON ERROR - AudioPlayer not available." in the console for every single balloon being spawned from then onwards indicating that my resource isn't being found?
At this time my SKEmitterNodes start to return nil as well. (2016-08-13 18:59:54.527 Stop & Pop[256:13785] *** -[NSKeyedUnarchiver initForReadingWithData:]: data is NULL)
Is there anything obvious I'm missing that could be causing these errors?
I hope I've provided enough information, thank you for reading.
No... this won't work. You have to instantiate the audioPlayer variable into the Class Level.
I tried to do this, instantiated the var audioPlayer on another ViewController at the Class Level.
Your best bet is to localize this method into your ViewController, and put the audioPlayer here:
class YourClassName : Type {
var audioPlayer : AVAudioPlayer?
yourMethodForCalling() {
}
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")