Using multiple AKPlayers for multiple audio files playback

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP



Using multiple AKPlayers for multiple audio files playback



I am trying to play 4 mp3 files synchronously using AudioKit's AKPlayer, and it was pretty successful. As a part of my Swift study, though, I wanted to simplify my code using arrays (or something I haven't learned yet) since I feel there's something redundant in my code, simply copying player codes for four times. Below is the code I've written:


let file1 = try? AKAudioFile(readFileName: "mixing_1_vocal.mp3")
let file2 = try? AKAudioFile(readFileName: "mixing_2_drums.mp3")
let file3 = try? AKAudioFile(readFileName: "mixing_3_synth.mp3")
let file4 = try? AKAudioFile(readFileName: "mixing_4_bass.mp3")


let player1 = AKPlayer(audioFile: file1!)
let player2 = AKPlayer(audioFile: file2!)
let player3 = AKPlayer(audioFile: file3!)
let player4 = AKPlayer(audioFile: file4!)
let startTime = AVAudioTime.now() + 0.25

let mixer = AKMixer()
player1 >>> mixer
player2 >>> mixer
player3 >>> mixer
player4 >>> mixer

player1.isLooping = true
player1.buffering = .always
player2.isLooping = true
player2.buffering = .always
player3.isLooping = true
player3.buffering = .always
player4.isLooping = true
player4.buffering = .always

AudioKit.output = mixer

try? AudioKit.start()
player1.start(at: startTime)
player2.start(at: startTime)
player3.start(at: startTime)
player4.start(at: startTime)



This is it! There are four different tracks (individual instruments), and they are supposed to be played at the same time, looped infinitely. It will be very helpful if anybody could help me improve my code. Are there better ways to perform the same work?




1 Answer
1



This is a pretty open ended question, but here's an example ViewController for iOS.


class ViewController: UIViewController

let mixer = AKMixer()
let players: [AKPlayer] =
do
let filenames = ["mixing_1_vocal.mp3",
"mixing_2_drums.mp3",
"mixing_3_synth.mp3",
"mixing_4_bass.mp3"]

return try filenames.map AKPlayer(audioFile: try AKAudioFile(readFileName: $0))
catch
fatalError()

()


override func viewDidLoad()
super.viewDidLoad()

makeConnections()
startAudioEngine()
preparePlayers()
startPlayers()


func makeConnections()
players.forEach $0 >>> mixer
AudioKit.output = mixer


func startAudioEngine()
do
try AudioKit.start()
catch
print(error)
fatalError()



func preparePlayers()
players.forEach player in
player.isLooping = true
player.buffering = .always
player.prepare()



func startPlayers()
let startTime = AVAudioTime.now() + 0.25
players.forEach $0.start(at: startTime)





Key points:



Use do try expression catch error , not try? expression. While convenient to ignore an error, it will quickly bite you down the road.


do try expression catch error


try? expression



Map and forEach, map is crucial for working with arrays. Notice how an array of filenames is transformed into an array of AKPlayers. Related, shorthand argument names: players.forEach player in player.play() is the same as players.forEach $0.play() . Also related, map re-throws, so you can try inside of map's closure.


players.forEach player in player.play()


players.forEach $0.play()



Use closures to encapsulate. The players variable is populated as it's defined using an immediately evaluated closure. The alternative is to have to create this array on init, then later populate it.



Finally, separate logic into functions as much as possible. It makes your code more readable, and easier to maintain.






By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Popular posts from this blog

Firebase Auth - with Email and Password - Check user already registered

Dynamically update html content plain JS

How to determine optimal route across keyboard