I have an array of audio instructions that I would like to randomize, play (one at a time), and do some data recording in between each instruction.
With the below code, I have a button press that triggers beginTest(), but the instruction tracks play simultaneously. It never gets to startRecord().
I've tried placing startRecord() inside audioPlayerDidFinishPlaying; in that case it does get to startRecord() for the first track, but doesn't continue to the next iteration of the loop inside beginTest() where playScript() is called.
func audioPlayerDidFinishPlaying(_ player: AVAudioPlayer, successfully flag: Bool)
{
self.player = nil
print("finished playing this file")
}
func playScript(c: String)
{
let path = Bundle.main.path(forResource: c, ofType:"m4a")!
let url = URL(fileURLWithPath: path)
do {
self.player = try AVAudioPlayer(contentsOf: url)
self.player?.delegate = self
self.player?.play()
print(c)
print("playing script for " + c)
} catch {
print("couldn't load script")
}
}
func beginTest()
{
for c in conditions.shuffled()
{
playScript(c: c)
if self.player == nil
{
startRecord()
print("started data recording")
}
}
exportData()
}
I'm guessing that beginTest() keeps moving along the for loop before audioPlayerDidFinishPlaying resets the player to nil, but I don't know how to stall this.
The approach using audioPlayerDidFinishPlaying(_:,successfully:)
is correct. In your code when you call playScript(c:)
you will iterate through all audio files from conditions
array and call startRecord
method really quickly, while first audio is playing. All sounds will be placed in a queue and play one by one. I don't know contents of startRecord
method, but I don't think that it was supposed to be called like that.
In order to avoid those problems you need to call playScript(c:)
and then wait for method startRecord()
to finish, and then call playScript(c:)
again. So you can try something like this:
import AVFoundation
class SomeClass: NSObject, AVAudioPlayerDelegate {
var player: AVAudioPlayer?
var conditions = [String]()
var instructions: [() -> ()] = []
func audioPlayerDidFinishPlaying(_ player: AVAudioPlayer, successfully flag: Bool) {
print("finished playing \(player.url)")
startRecord {
playNextInstruction()
}
}
func playScript(c: String)
{
let path = Bundle.main.path(forResource: c, ofType:"m4a")!
let url = URL(fileURLWithPath: path)
do {
self.player = try AVAudioPlayer(contentsOf: url)
self.player?.delegate = self
self.player?.play()
print(c)
print("playing script for " + c)
} catch {
print("couldn't load script")
}
}
func beginTest() {
instructions = conditions.shuffled().map { [unowned self] condition in
return {
self.playScript(c: condition)
}
}
playNextInstruction()
}
func playNextInstruction() {
if instructions.count != 0 {
instructions.remove(at: 0)()
} else {
exportData()
}
}
func exportData() {
}
func startRecord(completion: (() -> ())) {
}
}
If it won't work then I suggest to try searching problem somewhere else in your code.