Reputation: 53
I am very new to swift and I was a novice with Objective-C. Recently I started a soundboard app that plays many sounds on 3 different view controllers. For the apps next update I wanted to make it so it could play multiple sounds simultaneously and I did this by creating an individual audioPlayer for each button. So for each view controllers I would have 9 instances of AVAudioPlayers (One for each button) and when each button was pressed it would play one of them EX: audioPlayer8 would belong to the hitmarkerButton. I succesfully did this but now I want a way for the users to press a button to "reset" the sounds in the app. So for each view controller I already created an IBAction called stopPlayingSounds that should "reset" or stop playing all sounds from all view controllers. This is my first time asking a question here so please tell me if there is anything else I should include. Thank you.
Also each of the examples included below are just one of up to 9 examples for each view controller. PS - Each view controller is a page.
The "Sound Stopper" Button:
@IBAction func stopPlayingSounds(sender: AnyObject) {
}
An example of one of the buttons:
@IBAction func hitmarkerButton(sender: AnyObject) {
audioPlayer8 = AVAudioPlayer(contentsOfURL: hitmarkerSound, error: nil)
audioPlayer8.prepareToPlay()
audioPlayer8.play()
}
Example of one of the declarations of the AVAudioPlayers:
var audioPlayer8 = AVAudioPlayer()
And lastly, an example of the creation of the actual sound:
var hitmarkerSound = NSURL(fileURLWithPath: NSBundle.mainBundle().pathForResource("hitmarker", ofType: "mp3")!)
Upvotes: 1
Views: 3323
Reputation: 89
I struggled with this issue for weeks (overlaid audio from every stream that has been loaded). I eventually discovered that every let
statement creates a new instance of AVPlayer
, so the multi-threaded OS plays them all simultaneously. I solved my problem by creating a single AVPlayer
at the class level with:
var vidPlayer:AVPlayer = AVPlayer()
and then just reassigned vidPlayer
to new content each time with:
vidPlayer = AVPlayer(URL: url) //where url was defined previously
The player restarts with the new content and only the most current audio stream.
Upvotes: 3
Reputation: 46
I think you just need to initialize your variables somewhere other than inside the button press methods, so you can see those variables after the method is over. I always heard it "what happens in a method stays in a method..."
So for example I'd put the declarations at the top of your view controller, and stuff them in an array:
var myAudioPlayers = [AVAudioPlayer] //remember arrays start at 0 and go up to n-1
myAudioPlayers[0] = AVAudioPlayer(contentsOfURL: sound1, error: nil)
...
myAudioPlayers[8] = AVAudioPlayer(contentsOfURL: sound8, error: nil)
Then you'd have
@IBAction func hitmarkerButton(sender: AnyObject) {
audioPlayer[7].prepareToPlay()
audioPlayer[7].play()
}
And you can use the array to quickly do:
@IBAction func stopPlayingSounds(sender: AnyObject) {
foreach (ap in myAudioPlayers)
ap.stop()
}
Upvotes: 3